Annotation of sys/dev/pci/pcscp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pcscp.c,v 1.14 2006/04/30 00:35:40 brad Exp $ */
2: /* $NetBSD: pcscp.c,v 1.26 2003/10/19 10:25:42 tsutsui Exp $ */
3:
4: /*-
5: * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center; Izumi Tsutsui.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * pcscp.c: device dependent code for AMD Am53c974 (PCscsi-PCI)
43: * written by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
44: *
45: * Technical manual available at
46: * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/19113.pdf
47: */
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/device.h>
52: #include <sys/buf.h>
53:
54: #include <machine/bus.h>
55: #include <machine/intr.h>
56:
57: #include <scsi/scsi_all.h>
58: #include <scsi/scsiconf.h>
59: #include <scsi/scsi_message.h>
60:
61: #include <dev/pci/pcireg.h>
62: #include <dev/pci/pcivar.h>
63: #include <dev/pci/pcidevs.h>
64:
65: #include <dev/ic/ncr53c9xreg.h>
66: #include <dev/ic/ncr53c9xvar.h>
67:
68: #include <dev/pci/pcscpreg.h>
69:
70: #define IO_MAP_REG 0x10
71:
72: struct pcscp_softc {
73: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
74:
75: bus_space_tag_t sc_st; /* bus space tag */
76: bus_space_handle_t sc_sh; /* bus space handle */
77: void *sc_ih; /* interrupt cookie */
78:
79: bus_dma_tag_t sc_dmat; /* DMA tag */
80:
81: bus_dmamap_t sc_xfermap; /* DMA map for transfers */
82:
83: u_int32_t *sc_mdladdr; /* MDL array */
84: bus_dmamap_t sc_mdldmap; /* MDL DMA map */
85:
86: int sc_active; /* DMA state */
87: int sc_datain; /* DMA Data Direction */
88: size_t sc_dmasize; /* DMA size */
89: char **sc_dmaaddr; /* DMA address */
90: size_t *sc_dmalen; /* DMA length */
91: };
92:
93: #define READ_DMAREG(sc, reg) \
94: bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
95: #define WRITE_DMAREG(sc, reg, var) \
96: bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (var))
97:
98: #define PCSCP_READ_REG(sc, reg) \
99: bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2)
100: #define PCSCP_WRITE_REG(sc, reg, val) \
101: bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2, (val))
102:
103: int pcscp_match(struct device *, void *, void *);
104: void pcscp_attach(struct device *, struct device *, void *);
105:
106: struct cfattach pcscp_ca = {
107: sizeof(struct pcscp_softc), pcscp_match, pcscp_attach
108: };
109:
110: struct cfdriver pcscp_cd = {
111: NULL, "pcscp", DV_DULL
112: };
113:
114: /*
115: * Functions and the switch for the MI code.
116: */
117:
118: u_char pcscp_read_reg(struct ncr53c9x_softc *, int);
119: void pcscp_write_reg(struct ncr53c9x_softc *, int, u_char);
120: int pcscp_dma_isintr(struct ncr53c9x_softc *);
121: void pcscp_dma_reset(struct ncr53c9x_softc *);
122: int pcscp_dma_intr(struct ncr53c9x_softc *);
123: int pcscp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
124: size_t *, int, size_t *);
125: void pcscp_dma_go(struct ncr53c9x_softc *);
126: void pcscp_dma_stop(struct ncr53c9x_softc *);
127: int pcscp_dma_isactive(struct ncr53c9x_softc *);
128:
129: struct scsi_adapter pcscp_adapter = {
130: ncr53c9x_scsi_cmd, /* cmd */
131: minphys, /* minphys */
132: 0, /* open */
133: 0, /* close */
134: };
135:
136: struct ncr53c9x_glue pcscp_glue = {
137: pcscp_read_reg,
138: pcscp_write_reg,
139: pcscp_dma_isintr,
140: pcscp_dma_reset,
141: pcscp_dma_intr,
142: pcscp_dma_setup,
143: pcscp_dma_go,
144: pcscp_dma_stop,
145: pcscp_dma_isactive,
146: NULL, /* gl_clear_latched_intr */
147: };
148:
149: int
150: pcscp_match(struct device *parent, void *match, void *aux)
151: {
152: struct pci_attach_args *pa = aux;
153:
154: if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
155: return 0;
156:
157: switch (PCI_PRODUCT(pa->pa_id)) {
158: case PCI_PRODUCT_AMD_PCSCSI_PCI:
159: return 1;
160: }
161: return 0;
162: }
163:
164: /*
165: * Attach this instance, and then all the sub-devices
166: */
167: void
168: pcscp_attach(struct device *parent, struct device *self, void *aux)
169: {
170: struct pci_attach_args *pa = aux;
171: struct pcscp_softc *esc = (void *)self;
172: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
173: bus_space_tag_t iot;
174: bus_space_handle_t ioh;
175: pci_intr_handle_t ih;
176: const char *intrstr;
177: bus_dma_segment_t seg;
178: int error, rseg;
179:
180: if (pci_mapreg_map(pa, IO_MAP_REG, PCI_MAPREG_TYPE_IO, 0,
181: &iot, &ioh, NULL, NULL, NULL)) {
182: printf("%s: unable to map registers\n", sc->sc_dev.dv_xname);
183: return;
184: }
185:
186: sc->sc_glue = &pcscp_glue;
187:
188: esc->sc_st = iot;
189: esc->sc_sh = ioh;
190: esc->sc_dmat = pa->pa_dmat;
191:
192: /*
193: * XXX More of this should be in ncr53c9x_attach(), but
194: * XXX should we really poke around the chip that much in
195: * XXX the MI code? Think about this more...
196: */
197:
198: /*
199: * Set up static configuration info.
200: */
201:
202: /*
203: * XXX should read configuration from EEPROM?
204: *
205: * MI ncr53c9x driver does not support configuration
206: * per each target device, though...
207: */
208: sc->sc_id = 7;
209: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
210: sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE;
211: sc->sc_cfg3 = NCRAMDCFG3_IDM | NCRAMDCFG3_FCLK;
212: sc->sc_cfg4 = NCRAMDCFG4_GE12NS | NCRAMDCFG4_RADE;
213: sc->sc_rev = NCR_VARIANT_AM53C974;
214: sc->sc_features = NCR_F_FASTSCSI;
215: sc->sc_cfg3_fscsi = NCRAMDCFG3_FSCSI;
216: sc->sc_freq = 40; /* MHz */
217:
218: /*
219: * XXX minsync and maxxfer _should_ be set up in MI code,
220: * XXX but it appears to have some dependency on what sort
221: * XXX of DMA we're hooked up to, etc.
222: */
223:
224: /*
225: * This is the value used to start sync negotiations
226: * Note that the NCR register "SYNCTP" is programmed
227: * in "clocks per byte", and has a minimum value of 4.
228: * The SCSI period used in negotiation is one-fourth
229: * of the time (in nanoseconds) needed to transfer one byte.
230: * Since the chip's clock is given in MHz, we have the following
231: * formula: 4 * period = (1000 / freq) * 4
232: */
233:
234: sc->sc_minsync = 1000 / sc->sc_freq;
235:
236: /* Really no limit, but since we want to fit into the TCR... */
237: sc->sc_maxxfer = 16 * 1024 * 1024;
238:
239: /*
240: * Create the DMA maps for the data transfers.
241: */
242:
243: #define MDL_SEG_SIZE 0x1000 /* 4kbyte per segment */
244: #define MDL_SEG_OFFSET 0x0FFF
245: #define MDL_SIZE (MAXPHYS / MDL_SEG_SIZE + 1) /* no hardware limit? */
246:
247: if (bus_dmamap_create(esc->sc_dmat, MAXPHYS, MDL_SIZE, MDL_SEG_SIZE,
248: MDL_SEG_SIZE, BUS_DMA_NOWAIT, &esc->sc_xfermap)) {
249: printf("%s: can't create dma maps\n", sc->sc_dev.dv_xname);
250: return;
251: }
252:
253: /*
254: * Allocate and map memory for the MDL.
255: */
256:
257: if ((error = bus_dmamem_alloc(esc->sc_dmat,
258: sizeof(u_int32_t) * MDL_SIZE, PAGE_SIZE, 0, &seg, 1, &rseg,
259: BUS_DMA_NOWAIT)) != 0) {
260: printf("%s: unable to allocate memory for the MDL, "
261: "error = %d\n", sc->sc_dev.dv_xname, error);
262: goto fail_0;
263: }
264: if ((error = bus_dmamem_map(esc->sc_dmat, &seg, rseg,
265: sizeof(u_int32_t) * MDL_SIZE , (caddr_t *)&esc->sc_mdladdr,
266: BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
267: printf("%s: unable to map the MDL memory, error = %d\n",
268: sc->sc_dev.dv_xname, error);
269: goto fail_1;
270: }
271: if ((error = bus_dmamap_create(esc->sc_dmat,
272: sizeof(u_int32_t) * MDL_SIZE, 1, sizeof(u_int32_t) * MDL_SIZE,
273: 0, BUS_DMA_NOWAIT, &esc->sc_mdldmap)) != 0) {
274: printf("%s: unable to map_create for the MDL, error = %d\n",
275: sc->sc_dev.dv_xname, error);
276: goto fail_2;
277: }
278: if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_mdldmap,
279: esc->sc_mdladdr, sizeof(u_int32_t) * MDL_SIZE,
280: NULL, BUS_DMA_NOWAIT)) != 0) {
281: printf("%s: unable to load for the MDL, error = %d\n",
282: sc->sc_dev.dv_xname, error);
283: goto fail_3;
284: }
285:
286: /* map and establish interrupt */
287: if (pci_intr_map(pa, &ih)) {
288: printf(": couldn't map interrupt\n");
289: goto fail_4;
290: }
291:
292: intrstr = pci_intr_string(pa->pa_pc, ih);
293: esc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
294: ncr53c9x_intr, esc, sc->sc_dev.dv_xname);
295: if (esc->sc_ih == NULL) {
296: printf(": couldn't establish interrupt");
297: if (intrstr != NULL)
298: printf(" at %s", intrstr);
299: printf("\n");
300: goto fail_4;
301: }
302: if (intrstr != NULL)
303: printf(": %s\n", intrstr);
304:
305: /* Do the common parts of attachment. */
306: printf("%s", sc->sc_dev.dv_xname);
307:
308: ncr53c9x_attach(sc, &pcscp_adapter, NULL);
309:
310: /* Turn on target selection using the `dma' method */
311: sc->sc_features |= NCR_F_DMASELECT;
312:
313: return;
314:
315: fail_4:
316: bus_dmamap_unload(esc->sc_dmat, esc->sc_mdldmap);
317: fail_3:
318: bus_dmamap_destroy(esc->sc_dmat, esc->sc_mdldmap);
319: fail_2:
320: bus_dmamem_unmap(esc->sc_dmat, (caddr_t)esc->sc_mdldmap,
321: sizeof(uint32_t) * MDL_SIZE);
322: fail_1:
323: bus_dmamem_free(esc->sc_dmat, &seg, rseg);
324: fail_0:
325: bus_dmamap_destroy(esc->sc_dmat, esc->sc_xfermap);
326: }
327:
328: /*
329: * Glue functions.
330: */
331:
332: u_char
333: pcscp_read_reg(struct ncr53c9x_softc *sc, int reg)
334: {
335: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
336:
337: return PCSCP_READ_REG(esc, reg);
338: }
339:
340: void
341: pcscp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char v)
342: {
343: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
344:
345: PCSCP_WRITE_REG(esc, reg, v);
346: }
347:
348: int
349: pcscp_dma_isintr(struct ncr53c9x_softc *sc)
350: {
351: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
352:
353: return (PCSCP_READ_REG(esc, NCR_STAT) & NCRSTAT_INT) != 0;
354: }
355:
356: void
357: pcscp_dma_reset(struct ncr53c9x_softc *sc)
358: {
359: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
360:
361: WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE);
362:
363: esc->sc_active = 0;
364: }
365:
366: int
367: pcscp_dma_intr(struct ncr53c9x_softc *sc)
368: {
369: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
370: int trans, resid, i;
371: bus_dmamap_t dmap = esc->sc_xfermap;
372: int datain = esc->sc_datain;
373: u_int32_t dmastat;
374: char *p = NULL;
375:
376: dmastat = READ_DMAREG(esc, DMA_STAT);
377:
378: if (dmastat & DMASTAT_ERR) {
379: /* XXX not tested... */
380: WRITE_DMAREG(esc, DMA_CMD,
381: DMACMD_ABORT | (datain ? DMACMD_DIR : 0));
382:
383: printf("%s: error: DMA error detected; Aborting.\n",
384: sc->sc_dev.dv_xname);
385: bus_dmamap_unload(esc->sc_dmat, dmap);
386: return -1;
387: }
388:
389: if (dmastat & DMASTAT_ABT) {
390: /* XXX What should be done? */
391: printf("%s: dma_intr: DMA aborted.\n", sc->sc_dev.dv_xname);
392: WRITE_DMAREG(esc, DMA_CMD,
393: DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
394: esc->sc_active = 0;
395: return 0;
396: }
397:
398: #ifdef DIAGNOSTIC
399: /* This is an "assertion" :) */
400: if (esc->sc_active == 0)
401: panic("pcscp dmaintr: DMA wasn't active");
402: #endif
403:
404: /* DMA has stopped */
405:
406: esc->sc_active = 0;
407:
408: if (esc->sc_dmasize == 0) {
409: /* A "Transfer Pad" operation completed */
410: NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
411: PCSCP_READ_REG(esc, NCR_TCL) |
412: (PCSCP_READ_REG(esc, NCR_TCM) << 8),
413: PCSCP_READ_REG(esc, NCR_TCL),
414: PCSCP_READ_REG(esc, NCR_TCM)));
415: return 0;
416: }
417:
418: resid = 0;
419: /*
420: * If a transfer onto the SCSI bus gets interrupted by the device
421: * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
422: * as residual since the ESP counter registers get decremented as
423: * bytes are clocked into the FIFO.
424: */
425: if (!datain &&
426: (resid = (PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
427: NCR_DMA(("pcscp_dma_intr: empty esp FIFO of %d ", resid));
428: }
429:
430: if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
431: /*
432: * `Terminal count' is off, so read the residue
433: * out of the ESP counter registers.
434: */
435: if (datain) {
436: resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
437: while (resid > 1)
438: resid =
439: PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
440: WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_MDL |
441: (datain ? DMACMD_DIR : 0));
442:
443: for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */
444: if (READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP)
445: break;
446:
447: /* See the below comments... */
448: if (resid)
449: p = *esc->sc_dmaaddr;
450: }
451:
452: resid += PCSCP_READ_REG(esc, NCR_TCL) |
453: (PCSCP_READ_REG(esc, NCR_TCM) << 8) |
454: (PCSCP_READ_REG(esc, NCR_TCH) << 16);
455: } else {
456: while ((dmastat & DMASTAT_DONE) == 0)
457: dmastat = READ_DMAREG(esc, DMA_STAT);
458: }
459:
460: WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
461:
462: /* sync MDL */
463: bus_dmamap_sync(esc->sc_dmat, esc->sc_mdldmap,
464: 0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_POSTWRITE);
465: /* sync transfer buffer */
466: bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
467: datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
468: bus_dmamap_unload(esc->sc_dmat, dmap);
469:
470: trans = esc->sc_dmasize - resid;
471:
472: /*
473: * From the technical manual notes:
474: *
475: * `In some odd byte conditions, one residual byte will be left
476: * in the SCSI FIFO, and the FIFO flags will never count to 0.
477: * When this happens, the residual byte should be retrieved
478: * via PIO following completion of the BLAST operation.'
479: */
480:
481: if (p) {
482: p += trans;
483: *p = PCSCP_READ_REG(esc, NCR_FIFO);
484: trans++;
485: }
486:
487: if (trans < 0) { /* transferred < 0 ? */
488: #if 0
489: /*
490: * This situation can happen in perfectly normal operation
491: * if the ESP is reselected while using DMA to select
492: * another target. As such, don't print the warning.
493: */
494: printf("%s: xfer (%d) > req (%d)\n",
495: sc->sc_dev.dv_xname, trans, esc->sc_dmasize);
496: #endif
497: trans = esc->sc_dmasize;
498: }
499:
500: NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
501: PCSCP_READ_REG(esc, NCR_TCL),
502: PCSCP_READ_REG(esc, NCR_TCM),
503: PCSCP_READ_REG(esc, NCR_TCH),
504: trans, resid));
505:
506: *esc->sc_dmalen -= trans;
507: *esc->sc_dmaaddr += trans;
508:
509: return 0;
510: }
511:
512: int
513: pcscp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
514: int datain, size_t *dmasize)
515: {
516: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
517: bus_dmamap_t dmap = esc->sc_xfermap;
518: u_int32_t *mdl;
519: int error, nseg, seg;
520: bus_addr_t s_offset, s_addr;
521:
522: WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
523:
524: esc->sc_dmaaddr = addr;
525: esc->sc_dmalen = len;
526: esc->sc_dmasize = *dmasize;
527: esc->sc_datain = datain;
528:
529: #ifdef DIAGNOSTIC
530: if ((*dmasize / MDL_SEG_SIZE) > MDL_SIZE)
531: panic("pcscp: transfer size too large");
532: #endif
533:
534: /*
535: * No need to set up DMA in `Transfer Pad' operation.
536: * (case of *dmasize == 0)
537: */
538: if (*dmasize == 0)
539: return 0;
540:
541: error = bus_dmamap_load(esc->sc_dmat, dmap, *esc->sc_dmaaddr,
542: *esc->sc_dmalen, NULL,
543: ((sc->sc_nexus->xs->flags & SCSI_NOSLEEP) ?
544: BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_STREAMING |
545: ((sc->sc_nexus->xs->flags & SCSI_DATA_IN) ?
546: BUS_DMA_READ : BUS_DMA_WRITE));
547: if (error) {
548: printf("%s: unable to load dmamap, error = %d\n",
549: sc->sc_dev.dv_xname, error);
550: return error;
551: }
552:
553: /* set transfer length */
554: WRITE_DMAREG(esc, DMA_STC, *dmasize);
555:
556: /* set up MDL */
557: mdl = esc->sc_mdladdr;
558: nseg = dmap->dm_nsegs;
559:
560: /* the first segment is possibly not aligned with 4k MDL boundary */
561: s_addr = dmap->dm_segs[0].ds_addr;
562: s_offset = s_addr & MDL_SEG_OFFSET;
563: s_addr -= s_offset;
564:
565: /* set the first MDL and offset */
566: WRITE_DMAREG(esc, DMA_SPA, s_offset);
567: *mdl++ = htole32(s_addr);
568:
569: /* the rest dmamap segments are aligned with 4k boundary */
570: for (seg = 1; seg < nseg; seg++)
571: *mdl++ = htole32(dmap->dm_segs[seg].ds_addr);
572:
573: return 0;
574: }
575:
576: void
577: pcscp_dma_go(struct ncr53c9x_softc *sc)
578: {
579: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
580: bus_dmamap_t dmap = esc->sc_xfermap, mdldmap = esc->sc_mdldmap;
581: int datain = esc->sc_datain;
582:
583: /* No DMA transfer in Transfer Pad operation */
584: if (esc->sc_dmasize == 0)
585: return;
586:
587: /* sync transfer buffer */
588: bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
589: datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
590:
591: /* sync MDL */
592: bus_dmamap_sync(esc->sc_dmat, mdldmap,
593: 0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_PREWRITE);
594:
595: /* set Starting MDL Address */
596: WRITE_DMAREG(esc, DMA_SMDLA, mdldmap->dm_segs[0].ds_addr);
597:
598: /* set DMA command register bits */
599: /* XXX DMA Transfer Interrupt Enable bit is broken? */
600: WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | DMACMD_MDL |
601: /* DMACMD_INTE | */
602: (datain ? DMACMD_DIR : 0));
603:
604: /* issue DMA start command */
605: WRITE_DMAREG(esc, DMA_CMD, DMACMD_START | DMACMD_MDL |
606: /* DMACMD_INTE | */
607: (datain ? DMACMD_DIR : 0));
608:
609: esc->sc_active = 1;
610: }
611:
612: void
613: pcscp_dma_stop(struct ncr53c9x_softc *sc)
614: {
615: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
616:
617: /* dma stop */
618: /* XXX What should we do here ? */
619: WRITE_DMAREG(esc, DMA_CMD,
620: DMACMD_ABORT | (esc->sc_datain ? DMACMD_DIR : 0));
621: bus_dmamap_unload(esc->sc_dmat, esc->sc_xfermap);
622:
623: esc->sc_active = 0;
624: }
625:
626: int
627: pcscp_dma_isactive(struct ncr53c9x_softc *sc)
628: {
629: struct pcscp_softc *esc = (struct pcscp_softc *)sc;
630:
631: /* XXX should check esc->sc_active? */
632: if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE)
633: return 1;
634: return 0;
635: }
CVSweb