1 1.24 thorpej /* $NetBSD: asc.c,v 1.24 2023/12/20 15:29:05 thorpej Exp $ */ 2 1.1 wdk /*- 3 1.1 wdk * Copyright (c) 2000 The NetBSD Foundation, Inc. 4 1.1 wdk * All rights reserved. 5 1.1 wdk * 6 1.1 wdk * This code is derived from software contributed to The NetBSD Foundation 7 1.1 wdk * by Wayne Knowles 8 1.1 wdk * 9 1.1 wdk * Redistribution and use in source and binary forms, with or without 10 1.1 wdk * modification, are permitted provided that the following conditions 11 1.1 wdk * are met: 12 1.1 wdk * 1. Redistributions of source code must retain the above copyright 13 1.1 wdk * notice, this list of conditions and the following disclaimer. 14 1.1 wdk * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 wdk * notice, this list of conditions and the following disclaimer in the 16 1.1 wdk * documentation and/or other materials provided with the distribution. 17 1.1 wdk * 18 1.1 wdk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 wdk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 wdk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 wdk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 wdk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 wdk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 wdk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 wdk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 wdk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 wdk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 wdk * POSSIBILITY OF SUCH DAMAGE. 29 1.1 wdk */ 30 1.15 lukem 31 1.15 lukem #include <sys/cdefs.h> 32 1.24 thorpej __KERNEL_RCSID(0, "$NetBSD: asc.c,v 1.24 2023/12/20 15:29:05 thorpej Exp $"); 33 1.1 wdk 34 1.1 wdk #include <sys/types.h> 35 1.1 wdk #include <sys/param.h> 36 1.1 wdk #include <sys/systm.h> 37 1.1 wdk #include <sys/kernel.h> 38 1.1 wdk #include <sys/errno.h> 39 1.1 wdk #include <sys/device.h> 40 1.1 wdk #include <sys/buf.h> 41 1.1 wdk 42 1.13 thorpej #include <uvm/uvm_extern.h> 43 1.13 thorpej 44 1.1 wdk #include <dev/scsipi/scsi_all.h> 45 1.1 wdk #include <dev/scsipi/scsipi_all.h> 46 1.1 wdk #include <dev/scsipi/scsiconf.h> 47 1.1 wdk #include <dev/scsipi/scsi_message.h> 48 1.1 wdk 49 1.1 wdk #include <machine/cpu.h> 50 1.1 wdk #include <machine/autoconf.h> 51 1.1 wdk #include <machine/mainboard.h> 52 1.1 wdk #include <machine/bus.h> 53 1.1 wdk 54 1.1 wdk #include <mipsco/obio/rambo.h> 55 1.1 wdk 56 1.1 wdk #include <dev/ic/ncr53c9xreg.h> 57 1.1 wdk #include <dev/ic/ncr53c9xvar.h> 58 1.1 wdk 59 1.1 wdk struct asc_softc { 60 1.1 wdk struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ 61 1.1 wdk struct evcnt sc_intrcnt; /* Interrupt counter */ 62 1.1 wdk bus_space_tag_t sc_bst; 63 1.1 wdk bus_space_handle_t sc_bsh; /* NCR 53c94 registers */ 64 1.1 wdk bus_space_handle_t dm_bsh; /* RAMBO registers */ 65 1.1 wdk bus_dma_tag_t sc_dmat; 66 1.1 wdk bus_dmamap_t sc_dmamap; 67 1.21 tsutsui uint8_t **sc_dmaaddr; 68 1.1 wdk size_t *sc_dmalen; 69 1.1 wdk size_t sc_dmasize; 70 1.1 wdk int sc_flags; 71 1.1 wdk #define DMA_IDLE 0x0 72 1.1 wdk #define DMA_PULLUP 0x1 73 1.1 wdk #define DMA_ACTIVE 0x2 74 1.1 wdk #define DMA_MAPLOADED 0x4 75 1.21 tsutsui uint32_t dm_mode; 76 1.1 wdk int dm_curseg; 77 1.1 wdk }; 78 1.1 wdk 79 1.21 tsutsui static int ascmatch(device_t, cfdata_t, void *); 80 1.21 tsutsui static void ascattach(device_t, device_t, void *); 81 1.1 wdk 82 1.21 tsutsui CFATTACH_DECL_NEW(asc, sizeof(struct asc_softc), 83 1.12 thorpej ascmatch, ascattach, NULL, NULL); 84 1.1 wdk 85 1.1 wdk /* 86 1.1 wdk * Functions and the switch for the MI code. 87 1.1 wdk */ 88 1.21 tsutsui static uint8_t asc_read_reg(struct ncr53c9x_softc *, int); 89 1.21 tsutsui static void asc_write_reg(struct ncr53c9x_softc *, int, uint8_t); 90 1.21 tsutsui static int asc_dma_isintr(struct ncr53c9x_softc *); 91 1.21 tsutsui static void asc_dma_reset(struct ncr53c9x_softc *); 92 1.21 tsutsui static int asc_dma_intr(struct ncr53c9x_softc *); 93 1.21 tsutsui static int asc_dma_setup(struct ncr53c9x_softc *, uint8_t **, 94 1.6 matt size_t *, int, size_t *); 95 1.21 tsutsui static void asc_dma_go(struct ncr53c9x_softc *); 96 1.21 tsutsui static void asc_dma_stop(struct ncr53c9x_softc *); 97 1.21 tsutsui static int asc_dma_isactive(struct ncr53c9x_softc *); 98 1.1 wdk 99 1.1 wdk static struct ncr53c9x_glue asc_glue = { 100 1.1 wdk asc_read_reg, 101 1.1 wdk asc_write_reg, 102 1.1 wdk asc_dma_isintr, 103 1.1 wdk asc_dma_reset, 104 1.1 wdk asc_dma_intr, 105 1.1 wdk asc_dma_setup, 106 1.1 wdk asc_dma_go, 107 1.1 wdk asc_dma_stop, 108 1.1 wdk asc_dma_isactive, 109 1.1 wdk NULL, /* gl_clear_latched_intr */ 110 1.1 wdk }; 111 1.1 wdk 112 1.21 tsutsui static int asc_intr(void *); 113 1.3 wdk 114 1.21 tsutsui #define MAX_SCSI_XFER (64 * 1024) 115 1.1 wdk #define MAX_DMA_SZ MAX_SCSI_XFER 116 1.21 tsutsui #define DMA_SEGS (MAX_DMA_SZ / PAGE_SIZE) 117 1.1 wdk 118 1.1 wdk static int 119 1.21 tsutsui ascmatch(device_t parent, cfdata_t cf, void *aux) 120 1.1 wdk { 121 1.21 tsutsui 122 1.1 wdk return 1; 123 1.1 wdk } 124 1.1 wdk 125 1.1 wdk static void 126 1.21 tsutsui ascattach(device_t parent, device_t self, void *aux) 127 1.1 wdk { 128 1.21 tsutsui struct asc_softc *esc = device_private(self); 129 1.21 tsutsui struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 130 1.1 wdk struct confargs *ca = aux; 131 1.1 wdk 132 1.1 wdk /* 133 1.1 wdk * Set up glue for MI code early; we use some of it here. 134 1.1 wdk */ 135 1.21 tsutsui sc->sc_dev = self; 136 1.1 wdk sc->sc_glue = &asc_glue; 137 1.1 wdk 138 1.1 wdk esc->sc_bst = ca->ca_bustag; 139 1.1 wdk esc->sc_dmat = ca->ca_dmatag; 140 1.1 wdk 141 1.1 wdk if (bus_space_map(ca->ca_bustag, ca->ca_addr, 142 1.21 tsutsui 16 * 4, /* sizeof (ncr53c9xreg) */ 143 1.21 tsutsui BUS_SPACE_MAP_LINEAR, 144 1.21 tsutsui &esc->sc_bsh) != 0) { 145 1.21 tsutsui aprint_error(": cannot map registers\n"); 146 1.1 wdk return; 147 1.1 wdk } 148 1.1 wdk 149 1.1 wdk if (bus_space_map(ca->ca_bustag, RAMBO_BASE, sizeof(struct rambo_ch), 150 1.21 tsutsui BUS_SPACE_MAP_LINEAR, &esc->dm_bsh) != 0) { 151 1.21 tsutsui aprint_error(": cannot map DMA registers\n"); 152 1.1 wdk return; 153 1.1 wdk } 154 1.1 wdk 155 1.1 wdk if (bus_dmamap_create(esc->sc_dmat, MAX_DMA_SZ, 156 1.21 tsutsui DMA_SEGS, MAX_DMA_SZ, RB_BOUNDRY, BUS_DMA_WAITOK, 157 1.21 tsutsui &esc->sc_dmamap) != 0) { 158 1.21 tsutsui aprint_error(": failed to create dmamap\n"); 159 1.1 wdk return; 160 1.1 wdk } 161 1.1 wdk 162 1.1 wdk evcnt_attach_dynamic(&esc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 163 1.21 tsutsui device_xname(self), "intr"); 164 1.1 wdk 165 1.1 wdk esc->sc_flags = DMA_IDLE; 166 1.1 wdk asc_dma_reset(sc); 167 1.1 wdk 168 1.1 wdk /* Other settings */ 169 1.1 wdk sc->sc_id = 7; 170 1.1 wdk sc->sc_freq = 24; /* 24 MHz clock */ 171 1.1 wdk 172 1.1 wdk /* 173 1.1 wdk * Setup for genuine NCR 53C94 SCSI Controller 174 1.1 wdk */ 175 1.1 wdk 176 1.1 wdk sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; 177 1.7 wdk sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE; 178 1.7 wdk sc->sc_cfg3 = NCRCFG3_CDB | NCRCFG3_QTE | NCRCFG3_FSCSI; 179 1.1 wdk sc->sc_rev = NCR_VARIANT_NCR53C94; 180 1.1 wdk 181 1.1 wdk sc->sc_minsync = (1000 / sc->sc_freq) * 5 / 4; 182 1.1 wdk sc->sc_maxxfer = MAX_SCSI_XFER; 183 1.1 wdk 184 1.1 wdk #ifdef OLDNCR 185 1.21 tsutsui if (NCR_READ_REG(sc, NCR_CFG3) == 0) { 186 1.21 tsutsui aprint_normal(" [old revision]"); 187 1.1 wdk sc->sc_cfg2 = 0; 188 1.1 wdk sc->sc_cfg3 = 0; 189 1.1 wdk sc->sc_minsync = 0; 190 1.1 wdk } 191 1.1 wdk #endif 192 1.1 wdk 193 1.9 bouyer sc->sc_adapter.adapt_minphys = minphys; 194 1.9 bouyer sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 195 1.9 bouyer ncr53c9x_attach(sc); 196 1.1 wdk 197 1.3 wdk bus_intr_establish(esc->sc_bst, SYS_INTR_SCSI, 0, 0, asc_intr, esc); 198 1.1 wdk } 199 1.1 wdk 200 1.1 wdk /* 201 1.1 wdk * Glue functions. 202 1.1 wdk */ 203 1.1 wdk 204 1.21 tsutsui static uint8_t 205 1.6 matt asc_read_reg(struct ncr53c9x_softc *sc, int reg) 206 1.1 wdk { 207 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 208 1.1 wdk 209 1.1 wdk return bus_space_read_1(esc->sc_bst, esc->sc_bsh, reg * 4 + 3); 210 1.1 wdk } 211 1.1 wdk 212 1.6 matt static void 213 1.21 tsutsui asc_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 214 1.1 wdk { 215 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 216 1.1 wdk 217 1.1 wdk bus_space_write_1(esc->sc_bst, esc->sc_bsh, reg * 4 + 3, val); 218 1.1 wdk } 219 1.1 wdk 220 1.6 matt static void 221 1.6 matt dma_status(struct ncr53c9x_softc *sc) 222 1.1 wdk { 223 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 224 1.1 wdk int count; 225 1.1 wdk int stat; 226 1.1 wdk void *addr; 227 1.21 tsutsui uint32_t tc; 228 1.1 wdk 229 1.21 tsutsui tc = (asc_read_reg(sc, NCR_TCM) << 8) + asc_read_reg(sc, NCR_TCL); 230 1.1 wdk count = bus_space_read_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT); 231 1.1 wdk stat = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 232 1.21 tsutsui addr = (void *)bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_CADDR); 233 1.1 wdk 234 1.4 wdk printf("rambo status: cnt=%x addr=%p stat=%08x tc=%04x " 235 1.21 tsutsui "ncr_stat=0x%02x ncr_fifo=0x%02x\n", 236 1.21 tsutsui count, addr, stat, tc, 237 1.21 tsutsui asc_read_reg(sc, NCR_STAT), 238 1.21 tsutsui asc_read_reg(sc, NCR_FFLAG)); 239 1.4 wdk } 240 1.4 wdk 241 1.17 perry static inline void 242 1.6 matt check_fifo(struct asc_softc *esc) 243 1.4 wdk { 244 1.21 tsutsui int i = 100; 245 1.4 wdk 246 1.4 wdk while (i && !(bus_space_read_4(esc->sc_bst, esc->dm_bsh, 247 1.21 tsutsui RAMBO_MODE) & RB_FIFO_EMPTY)) { 248 1.21 tsutsui DELAY(1); 249 1.21 tsutsui i--; 250 1.4 wdk } 251 1.4 wdk 252 1.21 tsutsui if (i == 0) { 253 1.4 wdk dma_status((void *)esc); 254 1.4 wdk panic("fifo didn't flush"); 255 1.4 wdk } 256 1.1 wdk } 257 1.1 wdk 258 1.6 matt static int 259 1.6 matt asc_dma_isintr(struct ncr53c9x_softc *sc) 260 1.1 wdk { 261 1.21 tsutsui 262 1.1 wdk return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT; 263 1.1 wdk } 264 1.1 wdk 265 1.6 matt static void 266 1.6 matt asc_dma_reset(struct ncr53c9x_softc *sc) 267 1.1 wdk { 268 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 269 1.1 wdk 270 1.1 wdk bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, 0); 271 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 272 1.21 tsutsui RB_CLRFIFO|RB_CLRERROR); 273 1.1 wdk DELAY(10); 274 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 275 1.1 wdk 276 1.1 wdk if (esc->sc_flags & DMA_MAPLOADED) 277 1.1 wdk bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 278 1.1 wdk 279 1.1 wdk esc->sc_flags = DMA_IDLE; 280 1.1 wdk } 281 1.1 wdk 282 1.1 wdk /* 283 1.1 wdk * Setup a DMA transfer 284 1.1 wdk */ 285 1.1 wdk 286 1.1 wdk static int 287 1.21 tsutsui asc_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 288 1.21 tsutsui int datain, size_t *dmasize) 289 1.1 wdk { 290 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 291 1.1 wdk paddr_t paddr; 292 1.1 wdk size_t count, blocks; 293 1.1 wdk int prime, err; 294 1.1 wdk 295 1.1 wdk #ifdef DIAGNOSTIC 296 1.1 wdk if (esc->sc_flags & DMA_ACTIVE) { 297 1.1 wdk dma_status(sc); 298 1.1 wdk panic("DMA active"); 299 1.1 wdk } 300 1.1 wdk #endif 301 1.1 wdk 302 1.1 wdk esc->sc_dmaaddr = addr; 303 1.1 wdk esc->sc_dmalen = len; 304 1.1 wdk esc->sc_dmasize = *dmasize; 305 1.1 wdk esc->sc_flags = datain ? DMA_PULLUP : 0; 306 1.1 wdk 307 1.1 wdk NCR_DMA(("asc_dma_setup va=%p len=%d datain=%d count=%d\n", 308 1.21 tsutsui *addr, *len, datain, esc->sc_dmasize)); 309 1.1 wdk 310 1.5 wdk if (esc->sc_dmasize == 0) 311 1.5 wdk return 0; 312 1.5 wdk 313 1.23 andvar /* have dmamap for the transferring addresses */ 314 1.21 tsutsui if ((err = bus_dmamap_load(esc->sc_dmat, esc->sc_dmamap, 315 1.21 tsutsui *esc->sc_dmaaddr, esc->sc_dmasize, NULL /* kernel address */, BUS_DMA_NOWAIT)) != 0) 316 1.21 tsutsui panic("%s: bus_dmamap_load err=%d", 317 1.21 tsutsui device_xname(sc->sc_dev), err); 318 1.1 wdk 319 1.1 wdk esc->sc_flags |= DMA_MAPLOADED; 320 1.1 wdk 321 1.1 wdk paddr = esc->sc_dmamap->dm_segs[0].ds_addr; 322 1.1 wdk count = esc->sc_dmamap->dm_segs[0].ds_len; 323 1.21 tsutsui prime = (uint32_t)paddr & 0x3f; 324 1.7 wdk blocks = (prime + count + 63) >> 6; 325 1.1 wdk 326 1.21 tsutsui esc->dm_mode = datain ? RB_DMA_WR : RB_DMA_RD; 327 1.7 wdk 328 1.7 wdk /* Set transfer direction and disable DMA */ 329 1.7 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, esc->dm_mode); 330 1.1 wdk 331 1.1 wdk /* Load DMA transfer address */ 332 1.21 tsutsui bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_LADDR, paddr & ~0x3f); 333 1.1 wdk 334 1.7 wdk /* Load number of blocks to DMA (1 block = 64 bytes) */ 335 1.7 wdk bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, blocks); 336 1.1 wdk 337 1.1 wdk /* If non block-aligned transfer prime FIFO manually */ 338 1.1 wdk if (prime) { 339 1.7 wdk /* Enable DMA to prime the FIFO buffer */ 340 1.7 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, 341 1.21 tsutsui RAMBO_MODE, esc->dm_mode | RB_DMA_ENABLE); 342 1.7 wdk 343 1.1 wdk if (esc->sc_flags & DMA_PULLUP) { 344 1.5 wdk /* Read from NCR 53c94 controller*/ 345 1.21 tsutsui uint16_t *p; 346 1.4 wdk 347 1.21 tsutsui p = (uint16_t *)((uint32_t)*esc->sc_dmaaddr & ~0x3f); 348 1.5 wdk bus_space_write_multi_2(esc->sc_bst, esc->dm_bsh, 349 1.21 tsutsui RAMBO_FIFO, p, prime>>1); 350 1.7 wdk } else 351 1.7 wdk /* Write to NCR 53C94 controller */ 352 1.1 wdk while (prime > 0) { 353 1.21 tsutsui (void)bus_space_read_2(esc->sc_bst, esc->dm_bsh, 354 1.21 tsutsui RAMBO_FIFO); 355 1.1 wdk prime -= 2; 356 1.1 wdk } 357 1.7 wdk /* Leave DMA disabled while we setup NCR controller */ 358 1.7 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 359 1.21 tsutsui esc->dm_mode); 360 1.1 wdk } 361 1.10 wdk 362 1.10 wdk bus_dmamap_sync(esc->sc_dmat, esc->sc_dmamap, 0, esc->sc_dmasize, 363 1.21 tsutsui datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 364 1.7 wdk 365 1.1 wdk esc->dm_curseg = 0; 366 1.7 wdk esc->dm_mode |= RB_DMA_ENABLE; 367 1.7 wdk if (esc->sc_dmamap->dm_nsegs > 1) 368 1.7 wdk esc->dm_mode |= RB_INT_ENABLE; /* Requires DMA chaining */ 369 1.7 wdk 370 1.1 wdk return 0; 371 1.1 wdk } 372 1.1 wdk 373 1.6 matt static void 374 1.6 matt asc_dma_go(struct ncr53c9x_softc *sc) 375 1.1 wdk { 376 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 377 1.1 wdk 378 1.7 wdk /* Start DMA */ 379 1.7 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, esc->dm_mode); 380 1.7 wdk 381 1.1 wdk esc->sc_flags |= DMA_ACTIVE; 382 1.1 wdk } 383 1.1 wdk 384 1.6 matt static int 385 1.6 matt asc_dma_intr(struct ncr53c9x_softc *sc) 386 1.1 wdk { 387 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 388 1.1 wdk 389 1.1 wdk size_t resid, len; 390 1.1 wdk int trans; 391 1.21 tsutsui uint32_t status; 392 1.1 wdk u_int tcl, tcm; 393 1.1 wdk 394 1.1 wdk #ifdef DIAGNOSTIC 395 1.21 tsutsui if ((esc->sc_flags & DMA_ACTIVE) == 0) { 396 1.1 wdk dma_status(sc); 397 1.1 wdk panic("DMA not active"); 398 1.1 wdk } 399 1.1 wdk #endif 400 1.1 wdk 401 1.5 wdk resid = 0; 402 1.21 tsutsui if ((esc->sc_flags & DMA_PULLUP) == 0 && 403 1.5 wdk (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 404 1.1 wdk NCR_DMA(("asc_intr: empty FIFO of %d ", resid)); 405 1.1 wdk DELAY(10); 406 1.1 wdk } 407 1.4 wdk 408 1.5 wdk resid += (tcl = NCR_READ_REG(sc, NCR_TCL)) + 409 1.21 tsutsui ((tcm = NCR_READ_REG(sc, NCR_TCM)) << 8); 410 1.5 wdk 411 1.5 wdk if (esc->sc_dmasize == 0) { /* Transfer pad operation */ 412 1.5 wdk NCR_DMA(("asc_intr: discard %d bytes\n", resid)); 413 1.5 wdk return 0; 414 1.5 wdk } 415 1.5 wdk 416 1.1 wdk trans = esc->sc_dmasize - resid; 417 1.1 wdk if (trans < 0) { /* transferred < 0 ? */ 418 1.21 tsutsui printf("%s: xfer (%d) > req (%d)\n", 419 1.21 tsutsui __func__, trans, esc->sc_dmasize); 420 1.1 wdk trans = esc->sc_dmasize; 421 1.1 wdk } 422 1.1 wdk 423 1.1 wdk NCR_DMA(("asc_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n", 424 1.21 tsutsui tcl, tcm, trans, resid)); 425 1.1 wdk 426 1.1 wdk status = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 427 1.1 wdk 428 1.21 tsutsui if ((status & RB_FIFO_EMPTY) == 0) { /* Data left in RAMBO FIFO */ 429 1.21 tsutsui if ((esc->sc_flags & DMA_PULLUP) != 0) { /* SCSI Read */ 430 1.1 wdk paddr_t ptr; 431 1.21 tsutsui uint16_t *p; 432 1.1 wdk 433 1.4 wdk resid = status & 0x1f; 434 1.4 wdk 435 1.1 wdk /* take the address of block to fixed up */ 436 1.1 wdk ptr = bus_space_read_4(esc->sc_bst, esc->dm_bsh, 437 1.21 tsutsui RAMBO_CADDR); 438 1.1 wdk /* find the starting address of fractional data */ 439 1.21 tsutsui p = (uint16_t *)MIPS_PHYS_TO_KSEG0(ptr + (resid << 1)); 440 1.1 wdk 441 1.5 wdk /* duplicate trailing data to FIFO for force flush */ 442 1.1 wdk len = RB_BLK_CNT - resid; 443 1.5 wdk bus_space_write_multi_2(esc->sc_bst, esc->dm_bsh, 444 1.21 tsutsui RAMBO_FIFO, p, len); 445 1.4 wdk check_fifo(esc); 446 1.1 wdk } else { /* SCSI Write */ 447 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, 448 1.21 tsutsui RAMBO_MODE, 0); 449 1.4 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, 450 1.21 tsutsui RAMBO_MODE, RB_CLRFIFO); 451 1.1 wdk } 452 1.1 wdk } 453 1.1 wdk 454 1.4 wdk bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, 0); 455 1.4 wdk 456 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 457 1.1 wdk 458 1.1 wdk bus_dmamap_sync(esc->sc_dmat, esc->sc_dmamap, 459 1.21 tsutsui 0, esc->sc_dmasize, 460 1.21 tsutsui (esc->sc_flags & DMA_PULLUP) != 0 ? 461 1.21 tsutsui BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 462 1.1 wdk bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 463 1.4 wdk 464 1.21 tsutsui *esc->sc_dmaaddr += trans; 465 1.1 wdk *esc->sc_dmalen -= trans; 466 1.1 wdk 467 1.1 wdk esc->sc_flags = DMA_IDLE; 468 1.1 wdk 469 1.1 wdk return 0; 470 1.1 wdk } 471 1.1 wdk 472 1.1 wdk 473 1.6 matt static void 474 1.6 matt asc_dma_stop(struct ncr53c9x_softc *sc) 475 1.1 wdk { 476 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 477 1.1 wdk 478 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE, 0); 479 1.21 tsutsui if ((esc->sc_flags & DMA_MAPLOADED) != 0) 480 1.1 wdk bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap); 481 1.1 wdk esc->sc_flags = DMA_IDLE; 482 1.1 wdk } 483 1.1 wdk 484 1.6 matt static int 485 1.6 matt asc_dma_isactive(struct ncr53c9x_softc *sc) 486 1.1 wdk { 487 1.1 wdk struct asc_softc *esc = (struct asc_softc *)sc; 488 1.21 tsutsui return (esc->sc_flags & DMA_ACTIVE) != 0 ? 1 : 0; 489 1.1 wdk } 490 1.1 wdk 491 1.6 matt static void 492 1.6 matt rambo_dma_chain(struct asc_softc *esc) 493 1.1 wdk { 494 1.1 wdk int seg; 495 1.1 wdk size_t count, blocks; 496 1.1 wdk paddr_t paddr; 497 1.1 wdk 498 1.1 wdk seg = ++esc->dm_curseg; 499 1.1 wdk 500 1.1 wdk #ifdef DIAGNOSTIC 501 1.21 tsutsui if ((esc->sc_flags & DMA_ACTIVE) == 0 || seg > esc->sc_dmamap->dm_nsegs) 502 1.1 wdk panic("Unexpected DMA chaining intr"); 503 1.4 wdk 504 1.4 wdk /* Interrupt can only occur at terminal count, but double check */ 505 1.4 wdk if (bus_space_read_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT)) { 506 1.4 wdk dma_status((void *)esc); 507 1.4 wdk panic("rambo blkcnt != 0"); 508 1.4 wdk } 509 1.1 wdk #endif 510 1.1 wdk 511 1.1 wdk paddr = esc->sc_dmamap->dm_segs[seg].ds_addr; 512 1.1 wdk count = esc->sc_dmamap->dm_segs[seg].ds_len; 513 1.1 wdk blocks = (count + 63) >> 6; 514 1.1 wdk 515 1.1 wdk /* Disable DMA interrupt if last segment */ 516 1.21 tsutsui if (seg + 1 > esc->sc_dmamap->dm_nsegs) { 517 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, 518 1.21 tsutsui RAMBO_MODE, esc->dm_mode & ~RB_INT_ENABLE); 519 1.1 wdk } 520 1.1 wdk 521 1.1 wdk /* Load transfer address for next DMA chain */ 522 1.1 wdk bus_space_write_4(esc->sc_bst, esc->dm_bsh, RAMBO_LADDR, paddr); 523 1.1 wdk 524 1.1 wdk /* DMA restarts when we enter a new block count */ 525 1.1 wdk bus_space_write_2(esc->sc_bst, esc->dm_bsh, RAMBO_BLKCNT, blocks); 526 1.1 wdk } 527 1.1 wdk 528 1.6 matt static int 529 1.6 matt asc_intr(void *arg) 530 1.1 wdk { 531 1.21 tsutsui uint32_t dma_stat; 532 1.3 wdk struct asc_softc *esc = arg; 533 1.21 tsutsui struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 534 1.3 wdk 535 1.3 wdk esc->sc_intrcnt.ev_count++; 536 1.3 wdk 537 1.3 wdk /* Check for RAMBO DMA Interrupt */ 538 1.3 wdk dma_stat = bus_space_read_4(esc->sc_bst, esc->dm_bsh, RAMBO_MODE); 539 1.21 tsutsui if ((dma_stat & RB_INTR_PEND) != 0) { 540 1.3 wdk rambo_dma_chain(esc); 541 1.4 wdk } 542 1.4 wdk /* Check for NCR 53c94 interrupt */ 543 1.4 wdk if (NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT) { 544 1.4 wdk ncr53c9x_intr(sc); 545 1.3 wdk } 546 1.3 wdk return 0; 547 1.1 wdk } 548