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