1 /* $OpenBSD: pcscp.c,v 1.12 2006/04/18 19:52:09 martin 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(parent, match, aux) 151 struct device *parent; 152 void *match, *aux; 153 { 154 struct pci_attach_args *pa = aux; 155 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD) 156 return 0; 157 158 switch (PCI_PRODUCT(pa->pa_id)) { 159 case PCI_PRODUCT_AMD_PCSCSI_PCI: 160 return 1; 161 } 162 return 0; 163 } 164 165 /* 166 * Attach this instance, and then all the sub-devices 167 */ 168 void 169 pcscp_attach(parent, self, aux) 170 struct device *parent, *self; 171 void *aux; 172 { 173 struct pci_attach_args *pa = aux; 174 struct pcscp_softc *esc = (void *)self; 175 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 176 bus_space_tag_t iot; 177 bus_space_handle_t ioh; 178 pci_intr_handle_t ih; 179 const char *intrstr; 180 bus_dma_segment_t seg; 181 int error, rseg; 182 183 if (pci_mapreg_map(pa, IO_MAP_REG, PCI_MAPREG_TYPE_IO, 0, 184 &iot, &ioh, NULL, NULL, NULL)) { 185 printf("%s: unable to map registers\n", sc->sc_dev.dv_xname); 186 return; 187 } 188 189 sc->sc_glue = &pcscp_glue; 190 191 esc->sc_st = iot; 192 esc->sc_sh = ioh; 193 esc->sc_dmat = pa->pa_dmat; 194 195 /* 196 * XXX More of this should be in ncr53c9x_attach(), but 197 * XXX should we really poke around the chip that much in 198 * XXX the MI code? Think about this more... 199 */ 200 201 /* 202 * Set up static configuration info. 203 */ 204 205 /* 206 * XXX should read configuration from EEPROM? 207 * 208 * MI ncr53c9x driver does not support configuration 209 * per each target device, though... 210 */ 211 sc->sc_id = 7; 212 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; 213 sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE; 214 sc->sc_cfg3 = NCRAMDCFG3_IDM | NCRAMDCFG3_FCLK; 215 sc->sc_cfg4 = NCRAMDCFG4_GE12NS | NCRAMDCFG4_RADE; 216 sc->sc_rev = NCR_VARIANT_AM53C974; 217 sc->sc_features = NCR_F_FASTSCSI; 218 sc->sc_cfg3_fscsi = NCRAMDCFG3_FSCSI; 219 sc->sc_freq = 40; /* MHz */ 220 221 /* 222 * XXX minsync and maxxfer _should_ be set up in MI code, 223 * XXX but it appears to have some dependency on what sort 224 * XXX of DMA we're hooked up to, etc. 225 */ 226 227 /* 228 * This is the value used to start sync negotiations 229 * Note that the NCR register "SYNCTP" is programmed 230 * in "clocks per byte", and has a minimum value of 4. 231 * The SCSI period used in negotiation is one-fourth 232 * of the time (in nanoseconds) needed to transfer one byte. 233 * Since the chip's clock is given in MHz, we have the following 234 * formula: 4 * period = (1000 / freq) * 4 235 */ 236 237 sc->sc_minsync = 1000 / sc->sc_freq; 238 239 /* Really no limit, but since we want to fit into the TCR... */ 240 sc->sc_maxxfer = 16 * 1024 * 1024; 241 242 /* 243 * Create the DMA maps for the data transfers. 244 */ 245 246 #define MDL_SEG_SIZE 0x1000 /* 4kbyte per segment */ 247 #define MDL_SEG_OFFSET 0x0FFF 248 #define MDL_SIZE (MAXPHYS / MDL_SEG_SIZE + 1) /* no hardware limit? */ 249 250 if (bus_dmamap_create(esc->sc_dmat, MAXPHYS, MDL_SIZE, MDL_SEG_SIZE, 251 MDL_SEG_SIZE, BUS_DMA_NOWAIT, &esc->sc_xfermap)) { 252 printf("%s: can't create dma maps\n", sc->sc_dev.dv_xname); 253 return; 254 } 255 256 /* 257 * Allocate and map memory for the MDL. 258 */ 259 260 if ((error = bus_dmamem_alloc(esc->sc_dmat, 261 sizeof(u_int32_t) * MDL_SIZE, PAGE_SIZE, 0, &seg, 1, &rseg, 262 BUS_DMA_NOWAIT)) != 0) { 263 printf("%s: unable to allocate memory for the MDL, " 264 "error = %d\n", sc->sc_dev.dv_xname, error); 265 return; 266 } 267 if ((error = bus_dmamem_map(esc->sc_dmat, &seg, rseg, 268 sizeof(u_int32_t) * MDL_SIZE , (caddr_t *)&esc->sc_mdladdr, 269 BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) { 270 printf("%s: unable to map the MDL memory, error = %d\n", 271 sc->sc_dev.dv_xname, error); 272 goto fail_0; 273 } 274 if ((error = bus_dmamap_create(esc->sc_dmat, 275 sizeof(u_int32_t) * MDL_SIZE, 1, sizeof(u_int32_t) * MDL_SIZE, 276 0, BUS_DMA_NOWAIT, &esc->sc_mdldmap)) != 0) { 277 printf("%s: unable to map_create for the MDL, error = %d\n", 278 sc->sc_dev.dv_xname, error); 279 goto fail_1; 280 } 281 if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_mdldmap, 282 esc->sc_mdladdr, sizeof(u_int32_t) * MDL_SIZE, 283 NULL, BUS_DMA_NOWAIT)) != 0) { 284 printf("%s: unable to load for the MDL, error = %d\n", 285 sc->sc_dev.dv_xname, error); 286 goto fail_2; 287 } 288 289 /* map and establish interrupt */ 290 if (pci_intr_map(pa, &ih)) { 291 printf(": couldn't map interrupt\n"); 292 goto fail_3; 293 } 294 295 intrstr = pci_intr_string(pa->pa_pc, ih); 296 esc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, 297 ncr53c9x_intr, esc, sc->sc_dev.dv_xname); 298 if (esc->sc_ih == NULL) { 299 printf(": couldn't establish interrupt"); 300 if (intrstr != NULL) 301 printf(" at %s", intrstr); 302 printf("\n"); 303 goto fail_3; 304 } 305 if (intrstr != NULL) 306 printf(": %s\n", intrstr); 307 308 /* Do the common parts of attachment. */ 309 printf("%s", sc->sc_dev.dv_xname); 310 311 ncr53c9x_attach(sc, &pcscp_adapter, NULL); 312 313 /* Turn on target selection using the `dma' method */ 314 sc->sc_features |= NCR_F_DMASELECT; 315 316 return; 317 318 fail_3: 319 bus_dmamap_unload(esc->sc_dmat, esc->sc_mdldmap); 320 fail_2: 321 bus_dmamap_destroy(esc->sc_dmat, esc->sc_mdldmap); 322 fail_1: 323 bus_dmamem_unmap(esc->sc_dmat, (caddr_t)esc->sc_mdldmap, 324 sizeof(uint32_t) * MDL_SIZE); 325 fail_0: 326 bus_dmamem_free(esc->sc_dmat, &seg, rseg); 327 } 328 329 /* 330 * Glue functions. 331 */ 332 333 u_char 334 pcscp_read_reg(sc, reg) 335 struct ncr53c9x_softc *sc; 336 int reg; 337 { 338 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 339 340 return PCSCP_READ_REG(esc, reg); 341 } 342 343 void 344 pcscp_write_reg(sc, reg, v) 345 struct ncr53c9x_softc *sc; 346 int reg; 347 u_char v; 348 { 349 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 350 351 PCSCP_WRITE_REG(esc, reg, v); 352 } 353 354 int 355 pcscp_dma_isintr(sc) 356 struct ncr53c9x_softc *sc; 357 { 358 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 359 360 return (PCSCP_READ_REG(esc, NCR_STAT) & NCRSTAT_INT) != 0; 361 } 362 363 void 364 pcscp_dma_reset(sc) 365 struct ncr53c9x_softc *sc; 366 { 367 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 368 369 WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE); 370 371 esc->sc_active = 0; 372 } 373 374 int 375 pcscp_dma_intr(sc) 376 struct ncr53c9x_softc *sc; 377 { 378 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 379 int trans, resid, i; 380 bus_dmamap_t dmap = esc->sc_xfermap; 381 int datain = esc->sc_datain; 382 u_int32_t dmastat; 383 char *p = NULL; 384 385 dmastat = READ_DMAREG(esc, DMA_STAT); 386 387 if (dmastat & DMASTAT_ERR) { 388 /* XXX not tested... */ 389 WRITE_DMAREG(esc, DMA_CMD, 390 DMACMD_ABORT | (datain ? DMACMD_DIR : 0)); 391 392 printf("%s: error: DMA error detected; Aborting.\n", 393 sc->sc_dev.dv_xname); 394 bus_dmamap_unload(esc->sc_dmat, dmap); 395 return -1; 396 } 397 398 if (dmastat & DMASTAT_ABT) { 399 /* XXX What should be done? */ 400 printf("%s: dma_intr: DMA aborted.\n", sc->sc_dev.dv_xname); 401 WRITE_DMAREG(esc, DMA_CMD, 402 DMACMD_IDLE | (datain ? DMACMD_DIR : 0)); 403 esc->sc_active = 0; 404 return 0; 405 } 406 407 #ifdef DIAGNOSTIC 408 /* This is an "assertion" :) */ 409 if (esc->sc_active == 0) 410 panic("pcscp dmaintr: DMA wasn't active"); 411 #endif 412 413 /* DMA has stopped */ 414 415 esc->sc_active = 0; 416 417 if (esc->sc_dmasize == 0) { 418 /* A "Transfer Pad" operation completed */ 419 NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", 420 PCSCP_READ_REG(esc, NCR_TCL) | 421 (PCSCP_READ_REG(esc, NCR_TCM) << 8), 422 PCSCP_READ_REG(esc, NCR_TCL), 423 PCSCP_READ_REG(esc, NCR_TCM))); 424 return 0; 425 } 426 427 resid = 0; 428 /* 429 * If a transfer onto the SCSI bus gets interrupted by the device 430 * (e.g. for a SAVEPOINTER message), the data in the FIFO counts 431 * as residual since the ESP counter registers get decremented as 432 * bytes are clocked into the FIFO. 433 */ 434 if (!datain && 435 (resid = (PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 436 NCR_DMA(("pcscp_dma_intr: empty esp FIFO of %d ", resid)); 437 } 438 439 if ((sc->sc_espstat & NCRSTAT_TC) == 0) { 440 /* 441 * `Terminal count' is off, so read the residue 442 * out of the ESP counter registers. 443 */ 444 if (datain) { 445 resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF; 446 while (resid > 1) 447 resid = 448 PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF; 449 WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_MDL | 450 (datain ? DMACMD_DIR : 0)); 451 452 for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */ 453 if (READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP) 454 break; 455 456 /* See the below comments... */ 457 if (resid) 458 p = *esc->sc_dmaaddr; 459 } 460 461 resid += PCSCP_READ_REG(esc, NCR_TCL) | 462 (PCSCP_READ_REG(esc, NCR_TCM) << 8) | 463 (PCSCP_READ_REG(esc, NCR_TCH) << 16); 464 } else { 465 while ((dmastat & DMASTAT_DONE) == 0) 466 dmastat = READ_DMAREG(esc, DMA_STAT); 467 } 468 469 WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0)); 470 471 /* sync MDL */ 472 bus_dmamap_sync(esc->sc_dmat, esc->sc_mdldmap, 473 0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_POSTWRITE); 474 /* sync transfer buffer */ 475 bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize, 476 datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 477 bus_dmamap_unload(esc->sc_dmat, dmap); 478 479 trans = esc->sc_dmasize - resid; 480 481 /* 482 * From the technical manual notes: 483 * 484 * `In some odd byte conditions, one residual byte will be left 485 * in the SCSI FIFO, and the FIFO flags will never count to 0. 486 * When this happens, the residual byte should be retrieved 487 * via PIO following completion of the BLAST operation.' 488 */ 489 490 if (p) { 491 p += trans; 492 *p = PCSCP_READ_REG(esc, NCR_FIFO); 493 trans++; 494 } 495 496 if (trans < 0) { /* transferred < 0 ? */ 497 #if 0 498 /* 499 * This situation can happen in perfectly normal operation 500 * if the ESP is reselected while using DMA to select 501 * another target. As such, don't print the warning. 502 */ 503 printf("%s: xfer (%d) > req (%d)\n", 504 sc->sc_dev.dv_xname, trans, esc->sc_dmasize); 505 #endif 506 trans = esc->sc_dmasize; 507 } 508 509 NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", 510 PCSCP_READ_REG(esc, NCR_TCL), 511 PCSCP_READ_REG(esc, NCR_TCM), 512 PCSCP_READ_REG(esc, NCR_TCH), 513 trans, resid)); 514 515 *esc->sc_dmalen -= trans; 516 *esc->sc_dmaaddr += trans; 517 518 return 0; 519 } 520 521 int 522 pcscp_dma_setup(sc, addr, len, datain, dmasize) 523 struct ncr53c9x_softc *sc; 524 caddr_t *addr; 525 size_t *len; 526 int datain; 527 size_t *dmasize; 528 { 529 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 530 bus_dmamap_t dmap = esc->sc_xfermap; 531 u_int32_t *mdl; 532 int error, nseg, seg; 533 bus_addr_t s_offset, s_addr; 534 535 WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0)); 536 537 esc->sc_dmaaddr = addr; 538 esc->sc_dmalen = len; 539 esc->sc_dmasize = *dmasize; 540 esc->sc_datain = datain; 541 542 #ifdef DIAGNOSTIC 543 if ((*dmasize / MDL_SEG_SIZE) > MDL_SIZE) 544 panic("pcscp: transfer size too large"); 545 #endif 546 547 /* 548 * No need to set up DMA in `Transfer Pad' operation. 549 * (case of *dmasize == 0) 550 */ 551 if (*dmasize == 0) 552 return 0; 553 554 error = bus_dmamap_load(esc->sc_dmat, dmap, *esc->sc_dmaaddr, 555 *esc->sc_dmalen, NULL, 556 ((sc->sc_nexus->xs->flags & SCSI_NOSLEEP) ? 557 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_STREAMING | 558 ((sc->sc_nexus->xs->flags & SCSI_DATA_IN) ? 559 BUS_DMA_READ : BUS_DMA_WRITE)); 560 if (error) { 561 printf("%s: unable to load dmamap, error = %d\n", 562 sc->sc_dev.dv_xname, error); 563 return error; 564 } 565 566 /* set transfer length */ 567 WRITE_DMAREG(esc, DMA_STC, *dmasize); 568 569 /* set up MDL */ 570 mdl = esc->sc_mdladdr; 571 nseg = dmap->dm_nsegs; 572 573 /* the first segment is possibly not aligned with 4k MDL boundary */ 574 s_addr = dmap->dm_segs[0].ds_addr; 575 s_offset = s_addr & MDL_SEG_OFFSET; 576 s_addr -= s_offset; 577 578 /* set the first MDL and offset */ 579 WRITE_DMAREG(esc, DMA_SPA, s_offset); 580 *mdl++ = htole32(s_addr); 581 582 /* the rest dmamap segments are aligned with 4k boundary */ 583 for (seg = 1; seg < nseg; seg++) 584 *mdl++ = htole32(dmap->dm_segs[seg].ds_addr); 585 586 return 0; 587 } 588 589 void 590 pcscp_dma_go(sc) 591 struct ncr53c9x_softc *sc; 592 { 593 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 594 bus_dmamap_t dmap = esc->sc_xfermap, mdldmap = esc->sc_mdldmap; 595 int datain = esc->sc_datain; 596 597 /* No DMA transfer in Transfer Pad operation */ 598 if (esc->sc_dmasize == 0) 599 return; 600 601 /* sync transfer buffer */ 602 bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize, 603 datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 604 605 /* sync MDL */ 606 bus_dmamap_sync(esc->sc_dmat, mdldmap, 607 0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_PREWRITE); 608 609 /* set Starting MDL Address */ 610 WRITE_DMAREG(esc, DMA_SMDLA, mdldmap->dm_segs[0].ds_addr); 611 612 /* set DMA command register bits */ 613 /* XXX DMA Transfer Interrupt Enable bit is broken? */ 614 WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | DMACMD_MDL | 615 /* DMACMD_INTE | */ 616 (datain ? DMACMD_DIR : 0)); 617 618 /* issue DMA start command */ 619 WRITE_DMAREG(esc, DMA_CMD, DMACMD_START | DMACMD_MDL | 620 /* DMACMD_INTE | */ 621 (datain ? DMACMD_DIR : 0)); 622 623 esc->sc_active = 1; 624 } 625 626 void 627 pcscp_dma_stop(sc) 628 struct ncr53c9x_softc *sc; 629 { 630 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 631 632 /* dma stop */ 633 /* XXX What should we do here ? */ 634 WRITE_DMAREG(esc, DMA_CMD, 635 DMACMD_ABORT | (esc->sc_datain ? DMACMD_DIR : 0)); 636 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfermap); 637 638 esc->sc_active = 0; 639 } 640 641 int 642 pcscp_dma_isactive(sc) 643 struct ncr53c9x_softc *sc; 644 { 645 struct pcscp_softc *esc = (struct pcscp_softc *)sc; 646 647 /* XXX should check esc->sc_active? */ 648 if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE) 649 return 1; 650 return 0; 651 } 652