]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/esp/esp_pci.c
MFS r354090:
[FreeBSD/FreeBSD.git] / sys / dev / esp / esp_pci.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
3  *
4  * Copyright (c) 2011 Marius Strobl <marius@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*      $NetBSD: pcscp.c,v 1.45 2010/11/13 13:52:08 uebayasi Exp $      */
30
31 /*-
32  * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
33  * All rights reserved.
34  *
35  * This code is derived from software contributed to The NetBSD Foundation
36  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
37  * NASA Ames Research Center; Izumi Tsutsui.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60
61 /*
62  * esp_pci.c: device dependent code for AMD Am53c974 (PCscsi-PCI)
63  * written by Izumi Tsutsui <tsutsui@NetBSD.org>
64  *
65  * Technical manual available at
66  * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/19113.pdf
67  */
68
69 #include <sys/cdefs.h>
70 __FBSDID("$FreeBSD$");
71
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/bus.h>
75 #include <sys/endian.h>
76 #include <sys/kernel.h>
77 #include <sys/lock.h>
78 #include <sys/module.h>
79 #include <sys/mutex.h>
80 #include <sys/resource.h>
81 #include <sys/rman.h>
82
83 #include <machine/bus.h>
84 #include <machine/resource.h>
85
86 #include <cam/cam.h>
87 #include <cam/cam_ccb.h>
88 #include <cam/scsi/scsi_all.h>
89
90 #include <dev/pci/pcireg.h>
91 #include <dev/pci/pcivar.h>
92
93 #include <dev/esp/ncr53c9xreg.h>
94 #include <dev/esp/ncr53c9xvar.h>
95
96 #include <dev/esp/am53c974reg.h>
97
98 #define PCI_DEVICE_ID_AMD53C974 0x20201022
99
100 struct esp_pci_softc {
101         struct ncr53c9x_softc   sc_ncr53c9x;    /* glue to MI code */
102         device_t                sc_dev;
103
104         struct resource *sc_res[2];
105 #define ESP_PCI_RES_INTR        0
106 #define ESP_PCI_RES_IO          1
107
108         bus_dma_tag_t           sc_pdmat;
109
110         bus_dma_tag_t           sc_xferdmat;    /* DMA tag for transfers */
111         bus_dmamap_t            sc_xferdmam;    /* DMA map for transfers */
112
113         void                    *sc_ih;         /* interrupt handler */
114
115         size_t                  sc_dmasize;     /* DMA size */
116         void                    **sc_dmaaddr;   /* DMA address */
117         size_t                  *sc_dmalen;     /* DMA length */
118         int                     sc_active;      /* DMA state */
119         int                     sc_datain;      /* DMA Data Direction */
120 };
121
122 static struct resource_spec esp_pci_res_spec[] = {
123         { SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE },   /* ESP_PCI_RES_INTR */
124         { SYS_RES_IOPORT, PCIR_BAR(0), RF_ACTIVE },     /* ESP_PCI_RES_IO */
125         { -1, 0 }
126 };
127
128 #define READ_DMAREG(sc, reg)                                            \
129         bus_read_4((sc)->sc_res[ESP_PCI_RES_IO], (reg))
130 #define WRITE_DMAREG(sc, reg, var)                                      \
131         bus_write_4((sc)->sc_res[ESP_PCI_RES_IO], (reg), (var))
132
133 #define READ_ESPREG(sc, reg)                                            \
134         bus_read_1((sc)->sc_res[ESP_PCI_RES_IO], (reg) << 2)
135 #define WRITE_ESPREG(sc, reg, val)                                      \
136         bus_write_1((sc)->sc_res[ESP_PCI_RES_IO], (reg) << 2, (val))
137
138 static int      esp_pci_probe(device_t);
139 static int      esp_pci_attach(device_t);
140 static int      esp_pci_detach(device_t);
141 static int      esp_pci_suspend(device_t);
142 static int      esp_pci_resume(device_t);
143
144 static device_method_t esp_pci_methods[] = {
145         DEVMETHOD(device_probe,         esp_pci_probe),
146         DEVMETHOD(device_attach,        esp_pci_attach),
147         DEVMETHOD(device_detach,        esp_pci_detach),
148         DEVMETHOD(device_suspend,       esp_pci_suspend),
149         DEVMETHOD(device_resume,        esp_pci_resume),
150
151         DEVMETHOD_END
152 };
153
154 static driver_t esp_pci_driver = {
155         "esp",
156         esp_pci_methods,
157         sizeof(struct esp_pci_softc)
158 };
159
160 DRIVER_MODULE(esp, pci, esp_pci_driver, esp_devclass, 0, 0);
161 MODULE_DEPEND(esp, pci, 1, 1, 1);
162
163 /*
164  * Functions and the switch for the MI code
165  */
166 static void     esp_pci_dma_go(struct ncr53c9x_softc *);
167 static int      esp_pci_dma_intr(struct ncr53c9x_softc *);
168 static int      esp_pci_dma_isactive(struct ncr53c9x_softc *);
169
170 static int      esp_pci_dma_isintr(struct ncr53c9x_softc *);
171 static void     esp_pci_dma_reset(struct ncr53c9x_softc *);
172 static int      esp_pci_dma_setup(struct ncr53c9x_softc *, void **, size_t *,
173                     int, size_t *);
174 static void     esp_pci_dma_stop(struct ncr53c9x_softc *);
175 static void     esp_pci_write_reg(struct ncr53c9x_softc *, int, uint8_t);
176 static uint8_t  esp_pci_read_reg(struct ncr53c9x_softc *, int);
177 static void     esp_pci_xfermap(void *arg, bus_dma_segment_t *segs, int nseg,
178                     int error);
179
180 static struct ncr53c9x_glue esp_pci_glue = {
181         esp_pci_read_reg,
182         esp_pci_write_reg,
183         esp_pci_dma_isintr,
184         esp_pci_dma_reset,
185         esp_pci_dma_intr,
186         esp_pci_dma_setup,
187         esp_pci_dma_go,
188         esp_pci_dma_stop,
189         esp_pci_dma_isactive,
190 };
191
192 static int
193 esp_pci_probe(device_t dev)
194 {
195
196         if (pci_get_devid(dev) == PCI_DEVICE_ID_AMD53C974) {
197                 device_set_desc(dev, "AMD Am53C974 Fast-SCSI");
198                 return (BUS_PROBE_DEFAULT);
199         }
200
201         return (ENXIO);
202 }
203
204 /*
205  * Attach this instance, and then all the sub-devices
206  */
207 static int
208 esp_pci_attach(device_t dev)
209 {
210         struct esp_pci_softc *esc;
211         struct ncr53c9x_softc *sc;
212         int error;
213
214         esc = device_get_softc(dev);
215         sc = &esc->sc_ncr53c9x;
216
217         NCR_LOCK_INIT(sc);
218
219         esc->sc_dev = dev;
220         sc->sc_glue = &esp_pci_glue;
221
222         pci_enable_busmaster(dev);
223
224         error = bus_alloc_resources(dev, esp_pci_res_spec, esc->sc_res);
225         if (error != 0) {
226                 device_printf(dev, "failed to allocate resources\n");
227                 bus_release_resources(dev, esp_pci_res_spec, esc->sc_res);
228                 return (error);
229         }
230
231         error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
232             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
233             BUS_SPACE_MAXSIZE_32BIT, BUS_SPACE_UNRESTRICTED,
234             BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &esc->sc_pdmat);
235         if (error != 0) {
236                 device_printf(dev, "cannot create parent DMA tag\n");
237                 goto fail_res;
238         }
239
240         /*
241          * XXX More of this should be in ncr53c9x_attach(), but
242          * XXX should we really poke around the chip that much in
243          * XXX the MI code?  Think about this more...
244          */
245
246         /*
247          * Set up static configuration info.
248          *
249          * XXX we should read the configuration from the EEPROM.
250          */
251         sc->sc_id = 7;
252         sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
253         sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE;
254         sc->sc_cfg3 = NCRAMDCFG3_IDM | NCRAMDCFG3_FCLK;
255         sc->sc_cfg4 = NCRAMDCFG4_GE12NS | NCRAMDCFG4_RADE;
256         sc->sc_rev = NCR_VARIANT_AM53C974;
257         sc->sc_features = NCR_F_FASTSCSI | NCR_F_DMASELECT;
258         sc->sc_cfg3_fscsi = NCRAMDCFG3_FSCSI;
259         sc->sc_freq = 40; /* MHz */
260
261         /*
262          * This is the value used to start sync negotiations
263          * Note that the NCR register "SYNCTP" is programmed
264          * in "clocks per byte", and has a minimum value of 4.
265          * The SCSI period used in negotiation is one-fourth
266          * of the time (in nanoseconds) needed to transfer one byte.
267          * Since the chip's clock is given in MHz, we have the following
268          * formula: 4 * period = (1000 / freq) * 4
269          */
270         sc->sc_minsync = 1000 / sc->sc_freq;
271
272         sc->sc_maxxfer = DFLTPHYS;      /* see below */
273         sc->sc_maxoffset = 15;
274         sc->sc_extended_geom = 1;
275
276 #define MDL_SEG_SIZE    0x1000  /* 4kbyte per segment */
277
278         /*
279          * Create the DMA tag and map for the data transfers.
280          *
281          * Note: given that bus_dma(9) only adheres to the requested alignment
282          * for the first segment (and that also only for bus_dmamem_alloc()ed
283          * DMA maps) we can't use the Memory Descriptor List.  However, also
284          * when not using the MDL, the maximum transfer size apparently is
285          * limited to 4k so we have to split transfers up, which plain sucks.
286          */
287         error = bus_dma_tag_create(esc->sc_pdmat, PAGE_SIZE, 0,
288             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
289             MDL_SEG_SIZE, 1, MDL_SEG_SIZE, BUS_DMA_ALLOCNOW,
290             busdma_lock_mutex, &sc->sc_lock, &esc->sc_xferdmat);
291         if (error != 0) {
292                 device_printf(dev, "cannot create transfer DMA tag\n");
293                 goto fail_pdmat;
294         }
295         error = bus_dmamap_create(esc->sc_xferdmat, 0, &esc->sc_xferdmam);
296         if (error != 0) {
297                 device_printf(dev, "cannot create transfer DMA map\n");
298                 goto fail_xferdmat;
299         }
300
301         error = bus_setup_intr(dev, esc->sc_res[ESP_PCI_RES_INTR],
302             INTR_MPSAFE | INTR_TYPE_CAM, NULL, ncr53c9x_intr, sc,
303             &esc->sc_ih);
304         if (error != 0) {
305                 device_printf(dev, "cannot set up interrupt\n");
306                 goto fail_xferdmam;
307         }
308
309         /* Do the common parts of attachment. */
310         sc->sc_dev = esc->sc_dev;
311         error = ncr53c9x_attach(sc);
312         if (error != 0) {
313                 device_printf(esc->sc_dev, "ncr53c9x_attach failed\n");
314                 goto fail_intr;
315         }
316
317         return (0);
318
319  fail_intr:
320          bus_teardown_intr(esc->sc_dev, esc->sc_res[ESP_PCI_RES_INTR],
321             esc->sc_ih);
322  fail_xferdmam:
323         bus_dmamap_destroy(esc->sc_xferdmat, esc->sc_xferdmam);
324  fail_xferdmat:
325         bus_dma_tag_destroy(esc->sc_xferdmat);
326  fail_pdmat:
327         bus_dma_tag_destroy(esc->sc_pdmat);
328  fail_res:
329         bus_release_resources(dev, esp_pci_res_spec, esc->sc_res);
330         NCR_LOCK_DESTROY(sc);
331
332         return (error);
333 }
334
335 static int
336 esp_pci_detach(device_t dev)
337 {
338         struct ncr53c9x_softc *sc;
339         struct esp_pci_softc *esc;
340         int error;
341
342         esc = device_get_softc(dev);
343         sc = &esc->sc_ncr53c9x;
344
345         bus_teardown_intr(esc->sc_dev, esc->sc_res[ESP_PCI_RES_INTR],
346             esc->sc_ih);
347         error = ncr53c9x_detach(sc);
348         if (error != 0)
349                 return (error);
350         bus_dmamap_destroy(esc->sc_xferdmat, esc->sc_xferdmam);
351         bus_dma_tag_destroy(esc->sc_xferdmat);
352         bus_dma_tag_destroy(esc->sc_pdmat);
353         bus_release_resources(dev, esp_pci_res_spec, esc->sc_res);
354         NCR_LOCK_DESTROY(sc);
355
356         return (0);
357 }
358
359 static int
360 esp_pci_suspend(device_t dev)
361 {
362
363         return (ENXIO);
364 }
365
366 static int
367 esp_pci_resume(device_t dev)
368 {
369
370         return (ENXIO);
371 }
372
373 static void
374 esp_pci_xfermap(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
375 {
376         struct esp_pci_softc *esc = (struct esp_pci_softc *)arg;
377
378         if (error != 0)
379                 return;
380
381         KASSERT(nsegs == 1, ("%s: bad transfer segment count %d", __func__,
382             nsegs));
383         KASSERT(segs[0].ds_len <= MDL_SEG_SIZE,
384             ("%s: bad transfer segment length %ld", __func__,
385             (long)segs[0].ds_len));
386
387         /* Program the DMA Starting Physical Address. */
388         WRITE_DMAREG(esc, DMA_SPA, segs[0].ds_addr);
389 }
390
391 /*
392  * Glue functions
393  */
394
395 static uint8_t
396 esp_pci_read_reg(struct ncr53c9x_softc *sc, int reg)
397 {
398         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
399
400         return (READ_ESPREG(esc, reg));
401 }
402
403 static void
404 esp_pci_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t v)
405 {
406         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
407
408         WRITE_ESPREG(esc, reg, v);
409 }
410
411 static int
412 esp_pci_dma_isintr(struct ncr53c9x_softc *sc)
413 {
414         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
415
416         return (READ_ESPREG(esc, NCR_STAT) & NCRSTAT_INT) != 0;
417 }
418
419 static void
420 esp_pci_dma_reset(struct ncr53c9x_softc *sc)
421 {
422         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
423
424         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE);
425
426         esc->sc_active = 0;
427 }
428
429 static int
430 esp_pci_dma_intr(struct ncr53c9x_softc *sc)
431 {
432         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
433         bus_dma_tag_t xferdmat;
434         bus_dmamap_t xferdmam;
435         size_t dmasize;
436         int datain, i, resid, trans;
437         uint32_t dmastat;
438         char *p = NULL;
439
440         xferdmat = esc->sc_xferdmat;
441         xferdmam = esc->sc_xferdmam;
442         datain = esc->sc_datain;
443
444         dmastat = READ_DMAREG(esc, DMA_STAT);
445
446         if ((dmastat & DMASTAT_ERR) != 0) {
447                 /* XXX not tested... */
448                 WRITE_DMAREG(esc, DMA_CMD, DMACMD_ABORT | (datain != 0 ?
449                     DMACMD_DIR : 0));
450
451                 device_printf(esc->sc_dev, "DMA error detected; Aborting.\n");
452                 bus_dmamap_sync(xferdmat, xferdmam, datain != 0 ?
453                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
454                 bus_dmamap_unload(xferdmat, xferdmam);
455                 return (-1);
456         }
457
458         if ((dmastat & DMASTAT_ABT) != 0) {
459                 /* XXX what should be done? */
460                 device_printf(esc->sc_dev, "DMA aborted.\n");
461                 WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain != 0 ?
462                     DMACMD_DIR : 0));
463                 esc->sc_active = 0;
464                 return (0);
465         }
466
467         KASSERT(esc->sc_active != 0, ("%s: DMA wasn't active", __func__));
468
469         /* DMA has stopped. */
470
471         esc->sc_active = 0;
472
473         dmasize = esc->sc_dmasize;
474         if (dmasize == 0) {
475                 /* A "Transfer Pad" operation completed. */
476                 NCR_DMA(("%s: discarded %d bytes (tcl=%d, tcm=%d)\n",
477                     __func__, READ_ESPREG(esc, NCR_TCL) |
478                     (READ_ESPREG(esc, NCR_TCM) << 8),
479                     READ_ESPREG(esc, NCR_TCL), READ_ESPREG(esc, NCR_TCM)));
480                 return (0);
481         }
482
483         resid = 0;
484         /*
485          * If a transfer onto the SCSI bus gets interrupted by the device
486          * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
487          * as residual since the ESP counter registers get decremented as
488          * bytes are clocked into the FIFO.
489          */
490         if (datain == 0 &&
491             (resid = (READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0)
492                 NCR_DMA(("%s: empty esp FIFO of %d ", __func__, resid));
493
494         if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
495                 /*
496                  * "Terminal count" is off, so read the residue
497                  * out of the ESP counter registers.
498                  */
499                 if (datain != 0) {
500                         resid = READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF;
501                         while (resid > 1)
502                                 resid =
503                                     READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF;
504                         WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_DIR);
505
506                         for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */
507                                 if ((READ_DMAREG(esc, DMA_STAT) &
508                                     DMASTAT_BCMP) != 0)
509                                         break;
510
511                         /* See the below comments... */
512                         if (resid != 0)
513                                 p = *esc->sc_dmaaddr;
514                 }
515
516                 resid += READ_ESPREG(esc, NCR_TCL) |
517                     (READ_ESPREG(esc, NCR_TCM) << 8) |
518                     (READ_ESPREG(esc, NCR_TCH) << 16);
519         } else
520                 while ((dmastat & DMASTAT_DONE) == 0)
521                         dmastat = READ_DMAREG(esc, DMA_STAT);
522
523         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain != 0 ?
524             DMACMD_DIR : 0));
525
526         /* Sync the transfer buffer. */
527         bus_dmamap_sync(xferdmat, xferdmam, datain != 0 ?
528             BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
529         bus_dmamap_unload(xferdmat, xferdmam);
530
531         trans = dmasize - resid;
532
533         /*
534          * From the technical manual notes:
535          *
536          * "In some odd byte conditions, one residual byte will be left
537          *  in the SCSI FIFO, and the FIFO flags will never count to 0.
538          *  When this happens, the residual byte should be retrieved
539          *  via PIO following completion of the BLAST operation."
540          */
541         if (p != NULL) {
542                 p += trans;
543                 *p = READ_ESPREG(esc, NCR_FIFO);
544                 trans++;
545         }
546
547         if (trans < 0) {                        /* transferred < 0 ? */
548 #if 0
549                 /*
550                  * This situation can happen in perfectly normal operation
551                  * if the ESP is reselected while using DMA to select
552                  * another target.  As such, don't print the warning.
553                  */
554                 device_printf(dev, "xfer (%d) > req (%d)\n", trans, dmasize);
555 #endif
556                 trans = dmasize;
557         }
558
559         NCR_DMA(("%s: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", __func__,
560             READ_ESPREG(esc, NCR_TCL), READ_ESPREG(esc, NCR_TCM),
561             READ_ESPREG(esc, NCR_TCH), trans, resid));
562
563         *esc->sc_dmalen -= trans;
564         *esc->sc_dmaaddr = (char *)*esc->sc_dmaaddr + trans;
565
566         return (0);
567 }
568
569 static int
570 esp_pci_dma_setup(struct ncr53c9x_softc *sc, void **addr, size_t *len,
571     int datain, size_t *dmasize)
572 {
573         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
574         int error;
575
576         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain != 0 ? DMACMD_DIR :
577             0));
578
579         *dmasize = esc->sc_dmasize = ulmin(*dmasize, MDL_SEG_SIZE);
580         esc->sc_dmaaddr = addr;
581         esc->sc_dmalen = len;
582         esc->sc_datain = datain;
583
584         /*
585          * There's no need to set up DMA for a "Transfer Pad" operation.
586          */
587         if (*dmasize == 0)
588                 return (0);
589
590         /* Set the transfer length. */
591         WRITE_DMAREG(esc, DMA_STC, *dmasize);
592
593         /*
594          * Load the transfer buffer and program the DMA address.
595          * Note that the NCR53C9x core can't handle EINPROGRESS so we set
596          * BUS_DMA_NOWAIT.
597          */
598         error = bus_dmamap_load(esc->sc_xferdmat, esc->sc_xferdmam,
599             *esc->sc_dmaaddr, *dmasize, esp_pci_xfermap, sc, BUS_DMA_NOWAIT);
600
601         return (error);
602 }
603
604 static void
605 esp_pci_dma_go(struct ncr53c9x_softc *sc)
606 {
607         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
608         int datain;
609
610         datain = esc->sc_datain;
611
612         /* No DMA transfer for a "Transfer Pad" operation */
613         if (esc->sc_dmasize == 0)
614                 return;
615
616         /* Sync the transfer buffer. */
617         bus_dmamap_sync(esc->sc_xferdmat, esc->sc_xferdmam, datain != 0 ?
618             BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
619
620         /* Set the DMA engine to the IDLE state. */
621         /* XXX DMA Transfer Interrupt Enable bit is broken? */
622         WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | /* DMACMD_INTE | */
623             (datain != 0 ? DMACMD_DIR : 0));
624
625         /* Issue a DMA start command. */
626         WRITE_DMAREG(esc, DMA_CMD, DMACMD_START | /* DMACMD_INTE | */
627             (datain != 0 ? DMACMD_DIR : 0));
628
629         esc->sc_active = 1;
630 }
631
632 static void
633 esp_pci_dma_stop(struct ncr53c9x_softc *sc)
634 {
635         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
636
637         /* DMA stop */
638         /* XXX what should we do here ? */
639         WRITE_DMAREG(esc, DMA_CMD,
640             DMACMD_ABORT | (esc->sc_datain != 0 ? DMACMD_DIR : 0));
641         bus_dmamap_unload(esc->sc_xferdmat, esc->sc_xferdmam);
642
643         esc->sc_active = 0;
644 }
645
646 static int
647 esp_pci_dma_isactive(struct ncr53c9x_softc *sc)
648 {
649         struct esp_pci_softc *esc = (struct esp_pci_softc *)sc;
650
651         /* XXX should we check esc->sc_active? */
652         if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE)
653                 return (1);
654
655         return (0);
656 }