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