1 1.33 tsutsui /* $NetBSD: si_vme.c,v 1.33 2024/12/20 23:52:00 tsutsui Exp $ */ 2 1.1 gwr 3 1.7 gwr /*- 4 1.7 gwr * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 1.1 gwr * All rights reserved. 6 1.1 gwr * 7 1.7 gwr * This code is derived from software contributed to The NetBSD Foundation 8 1.7 gwr * by Adam Glass, David Jones, and Gordon W. Ross. 9 1.7 gwr * 10 1.1 gwr * Redistribution and use in source and binary forms, with or without 11 1.1 gwr * modification, are permitted provided that the following conditions 12 1.1 gwr * are met: 13 1.1 gwr * 1. Redistributions of source code must retain the above copyright 14 1.1 gwr * notice, this list of conditions and the following disclaimer. 15 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 gwr * notice, this list of conditions and the following disclaimer in the 17 1.1 gwr * documentation and/or other materials provided with the distribution. 18 1.1 gwr * 19 1.7 gwr * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.7 gwr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.7 gwr * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.9 gwr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.9 gwr * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.7 gwr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.7 gwr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.7 gwr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.7 gwr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.7 gwr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.7 gwr * POSSIBILITY OF SUCH DAMAGE. 30 1.1 gwr */ 31 1.1 gwr 32 1.1 gwr /* 33 1.1 gwr * This file contains only the machine-dependent parts of the 34 1.1 gwr * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) 35 1.1 gwr * The machine-independent parts are in ncr5380sbc.c 36 1.1 gwr * 37 1.1 gwr * Supported hardware includes: 38 1.1 gwr * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) 39 1.1 gwr * Sun SCSI-3 on VME (Sun3/160,Sun3/260) 40 1.1 gwr * 41 1.1 gwr * Could be made to support the Sun3/E if someone wanted to. 42 1.1 gwr * 43 1.1 gwr * Note: Both supported variants of the Sun SCSI-3 adapter have 44 1.1 gwr * some really unusual "features" for this driver to deal with, 45 1.1 gwr * generally related to the DMA engine. The OBIO variant will 46 1.1 gwr * ignore any attempt to write the FIFO count register while the 47 1.1 gwr * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with 48 1.1 gwr * by setting the FIFO count early in COMMAND or MSG_IN phase. 49 1.1 gwr * 50 1.1 gwr * The VME variant has a bit to enable or disable the DMA engine, 51 1.1 gwr * but that bit also gates the interrupt line from the NCR5380! 52 1.1 gwr * Therefore, in order to get any interrupt from the 5380, (i.e. 53 1.1 gwr * for reselect) one must clear the DMA engine transfer count and 54 1.1 gwr * then enable DMA. This has the further complication that you 55 1.1 gwr * CAN NOT touch the NCR5380 while the DMA enable bit is set, so 56 1.1 gwr * we have to turn DMA back off before we even look at the 5380. 57 1.1 gwr * 58 1.1 gwr * What wonderfully whacky hardware this is! 59 1.1 gwr * 60 1.1 gwr * Credits, history: 61 1.1 gwr * 62 1.1 gwr * David Jones wrote the initial version of this module, which 63 1.1 gwr * included support for the VME adapter only. (no reselection). 64 1.1 gwr * 65 1.1 gwr * Gordon Ross added support for the OBIO adapter, and re-worked 66 1.1 gwr * both the VME and OBIO code to support disconnect/reselect. 67 1.1 gwr * (Required figuring out the hardware "features" noted above.) 68 1.1 gwr * 69 1.1 gwr * The autoconfiguration boilerplate came from Adam Glass. 70 1.1 gwr */ 71 1.1 gwr 72 1.1 gwr /***************************************************************** 73 1.1 gwr * VME functions for DMA 74 1.1 gwr ****************************************************************/ 75 1.22 lukem 76 1.22 lukem #include <sys/cdefs.h> 77 1.33 tsutsui __KERNEL_RCSID(0, "$NetBSD: si_vme.c,v 1.33 2024/12/20 23:52:00 tsutsui Exp $"); 78 1.1 gwr 79 1.1 gwr #include <sys/param.h> 80 1.1 gwr #include <sys/systm.h> 81 1.1 gwr #include <sys/errno.h> 82 1.1 gwr #include <sys/kernel.h> 83 1.1 gwr #include <sys/device.h> 84 1.1 gwr #include <sys/buf.h> 85 1.1 gwr #include <sys/proc.h> 86 1.1 gwr 87 1.12 bouyer #include <dev/scsipi/scsi_all.h> 88 1.12 bouyer #include <dev/scsipi/scsipi_all.h> 89 1.12 bouyer #include <dev/scsipi/scsipi_debug.h> 90 1.12 bouyer #include <dev/scsipi/scsiconf.h> 91 1.1 gwr 92 1.1 gwr #include <machine/autoconf.h> 93 1.1 gwr #include <machine/dvma.h> 94 1.1 gwr 95 1.14 gwr /* #define DEBUG XXX */ 96 1.1 gwr 97 1.1 gwr #include <dev/ic/ncr5380reg.h> 98 1.1 gwr #include <dev/ic/ncr5380var.h> 99 1.1 gwr 100 1.1 gwr #include "sireg.h" 101 1.1 gwr #include "sivar.h" 102 1.1 gwr 103 1.23 chs void si_vme_dma_setup(struct ncr5380_softc *); 104 1.23 chs void si_vme_dma_start(struct ncr5380_softc *); 105 1.23 chs void si_vme_dma_eop(struct ncr5380_softc *); 106 1.23 chs void si_vme_dma_stop(struct ncr5380_softc *); 107 1.1 gwr 108 1.23 chs void si_vme_intr_on (struct ncr5380_softc *); 109 1.23 chs void si_vme_intr_off(struct ncr5380_softc *); 110 1.1 gwr 111 1.23 chs static void si_vme_reset(struct ncr5380_softc *); 112 1.13 gwr 113 1.1 gwr /* 114 1.1 gwr * New-style autoconfig attachment 115 1.1 gwr */ 116 1.1 gwr 117 1.28 tsutsui static int si_vme_match(device_t, cfdata_t, void *); 118 1.28 tsutsui static void si_vme_attach(device_t, device_t, void *); 119 1.1 gwr 120 1.28 tsutsui CFATTACH_DECL_NEW(si_vme, sizeof(struct si_softc), 121 1.19 thorpej si_vme_match, si_vme_attach, NULL, NULL); 122 1.1 gwr 123 1.10 gwr /* 124 1.10 gwr * Options for disconnect/reselect, DMA, and interrupts. 125 1.10 gwr * By default, allow disconnect/reselect on targets 4-6. 126 1.10 gwr * Those are normally tapes that really need it enabled. 127 1.10 gwr */ 128 1.10 gwr int si_vme_options = 0x0f; 129 1.1 gwr 130 1.1 gwr 131 1.33 tsutsui static int 132 1.28 tsutsui si_vme_match(device_t parent, cfdata_t cf, void *aux) 133 1.1 gwr { 134 1.13 gwr struct confargs *ca = aux; 135 1.5 gwr int probe_addr; 136 1.1 gwr 137 1.13 gwr /* No default VME address. */ 138 1.1 gwr if (ca->ca_paddr == -1) 139 1.28 tsutsui return 0; 140 1.1 gwr 141 1.13 gwr /* Make sure something is there... */ 142 1.5 gwr probe_addr = ca->ca_paddr + 1; 143 1.5 gwr if (bus_peek(ca->ca_bustype, probe_addr, 1) == -1) 144 1.28 tsutsui return 0; 145 1.1 gwr 146 1.1 gwr /* 147 1.1 gwr * If this is a VME SCSI board, we have to determine whether 148 1.1 gwr * it is an "sc" (Sun2) or "si" (Sun3) SCSI board. This can 149 1.1 gwr * be determined using the fact that the "sc" board occupies 150 1.1 gwr * 4K bytes in VME space but the "si" board occupies 2K bytes. 151 1.1 gwr */ 152 1.1 gwr /* Note: the "si" board should NOT respond here. */ 153 1.5 gwr probe_addr = ca->ca_paddr + 0x801; 154 1.5 gwr if (bus_peek(ca->ca_bustype, probe_addr, 1) != -1) { 155 1.1 gwr /* Something responded at 2K+1. Maybe an "sc" board? */ 156 1.1 gwr #ifdef DEBUG 157 1.28 tsutsui printf("%s: May be an `sc' board at pa=0x%lx\n", 158 1.28 tsutsui __func__, ca->ca_paddr); 159 1.1 gwr #endif 160 1.28 tsutsui return 0; 161 1.1 gwr } 162 1.1 gwr 163 1.13 gwr /* Default interrupt priority. */ 164 1.5 gwr if (ca->ca_intpri == -1) 165 1.5 gwr ca->ca_intpri = 2; 166 1.5 gwr 167 1.28 tsutsui return 1; 168 1.1 gwr } 169 1.1 gwr 170 1.33 tsutsui static void 171 1.28 tsutsui si_vme_attach(device_t parent, device_t self, void *args) 172 1.1 gwr { 173 1.28 tsutsui struct si_softc *sc = device_private(self); 174 1.5 gwr struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 175 1.25 thorpej struct cfdata *cf = device_cfdata(self); 176 1.1 gwr struct confargs *ca = args; 177 1.1 gwr 178 1.28 tsutsui ncr_sc->sc_dev = self; 179 1.26 tsutsui sc->sc_bst = ca->ca_bustag; 180 1.26 tsutsui sc->sc_dmat = ca->ca_dmatag; 181 1.26 tsutsui 182 1.26 tsutsui if (bus_space_map(sc->sc_bst, ca->ca_paddr, sizeof(struct si_regs), 0, 183 1.26 tsutsui &sc->sc_bsh) != 0) { 184 1.28 tsutsui aprint_error(": can't map register\n"); 185 1.26 tsutsui return; 186 1.26 tsutsui } 187 1.26 tsutsui sc->sc_regs = bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 188 1.26 tsutsui 189 1.26 tsutsui if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0, 190 1.26 tsutsui BUS_DMA_NOWAIT, &sc->sc_dmap) != 0) { 191 1.28 tsutsui aprint_error(": can't create DMA map\n"); 192 1.26 tsutsui return; 193 1.26 tsutsui } 194 1.26 tsutsui 195 1.10 gwr /* Get options from config flags if specified. */ 196 1.10 gwr if (cf->cf_flags) 197 1.10 gwr sc->sc_options = cf->cf_flags; 198 1.10 gwr else 199 1.10 gwr sc->sc_options = si_vme_options; 200 1.10 gwr 201 1.28 tsutsui aprint_normal(": options=0x%x\n", sc->sc_options); 202 1.1 gwr 203 1.1 gwr sc->sc_adapter_type = ca->ca_bustype; 204 1.26 tsutsui sc->sc_adapter_iv_am = VME_SUPV_DATA_24 | (ca->ca_intvec & 0xFF); 205 1.1 gwr 206 1.1 gwr /* 207 1.1 gwr * MD function pointers used by the MI code. 208 1.1 gwr */ 209 1.1 gwr ncr_sc->sc_pio_out = ncr5380_pio_out; 210 1.1 gwr ncr_sc->sc_pio_in = ncr5380_pio_in; 211 1.1 gwr ncr_sc->sc_dma_alloc = si_dma_alloc; 212 1.1 gwr ncr_sc->sc_dma_free = si_dma_free; 213 1.1 gwr ncr_sc->sc_dma_setup = si_vme_dma_setup; 214 1.1 gwr ncr_sc->sc_dma_start = si_vme_dma_start; 215 1.2 gwr ncr_sc->sc_dma_poll = si_dma_poll; 216 1.2 gwr ncr_sc->sc_dma_eop = si_vme_dma_eop; 217 1.1 gwr ncr_sc->sc_dma_stop = si_vme_dma_stop; 218 1.1 gwr ncr_sc->sc_intr_on = si_vme_intr_on; 219 1.1 gwr ncr_sc->sc_intr_off = si_vme_intr_off; 220 1.1 gwr 221 1.1 gwr /* Attach interrupt handler. */ 222 1.26 tsutsui isr_add_vectored(si_intr, (void *)sc, ca->ca_intpri, ca->ca_intvec); 223 1.1 gwr 224 1.13 gwr /* Reset the hardware. */ 225 1.13 gwr si_vme_reset(ncr_sc); 226 1.13 gwr 227 1.1 gwr /* Do the common attach stuff. */ 228 1.1 gwr si_attach(sc); 229 1.1 gwr } 230 1.1 gwr 231 1.13 gwr static void 232 1.13 gwr si_vme_reset(struct ncr5380_softc *ncr_sc) 233 1.13 gwr { 234 1.13 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 235 1.13 gwr volatile struct si_regs *si = sc->sc_regs; 236 1.13 gwr 237 1.13 gwr #ifdef DEBUG 238 1.13 gwr if (si_debug) { 239 1.28 tsutsui printf("%s\n", __func__); 240 1.13 gwr } 241 1.13 gwr #endif 242 1.13 gwr 243 1.13 gwr /* 244 1.13 gwr * The SCSI3 controller has an 8K FIFO to buffer data between the 245 1.13 gwr * 5380 and the DMA. Make sure it starts out empty. 246 1.13 gwr * 247 1.13 gwr * The reset bits in the CSR are active low. 248 1.13 gwr */ 249 1.13 gwr si->si_csr = 0; 250 1.13 gwr delay(10); 251 1.13 gwr si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES | SI_CSR_INTR_EN; 252 1.13 gwr delay(10); 253 1.13 gwr si->fifo_count = 0; 254 1.13 gwr 255 1.13 gwr /* Make sure the DMA engine is stopped. */ 256 1.13 gwr si->dma_addrh = 0; 257 1.13 gwr si->dma_addrl = 0; 258 1.13 gwr si->dma_counth = 0; 259 1.13 gwr si->dma_countl = 0; 260 1.13 gwr si->si_iv_am = sc->sc_adapter_iv_am; 261 1.13 gwr si->fifo_cnt_hi = 0; 262 1.13 gwr } 263 1.1 gwr 264 1.1 gwr /* 265 1.1 gwr * This is called when the bus is going idle, 266 1.1 gwr * so we want to enable the SBC interrupts. 267 1.1 gwr * That is controlled by the DMA enable! 268 1.1 gwr * Who would have guessed! 269 1.1 gwr * What a NASTY trick! 270 1.1 gwr */ 271 1.33 tsutsui void 272 1.23 chs si_vme_intr_on(struct ncr5380_softc *ncr_sc) 273 1.1 gwr { 274 1.1 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 275 1.1 gwr volatile struct si_regs *si = sc->sc_regs; 276 1.1 gwr 277 1.2 gwr /* receive mode should be safer */ 278 1.2 gwr si->si_csr &= ~SI_CSR_SEND; 279 1.2 gwr 280 1.2 gwr /* Clear the count so nothing happens. */ 281 1.2 gwr si->dma_counth = 0; 282 1.2 gwr si->dma_countl = 0; 283 1.2 gwr 284 1.2 gwr /* Clear the start address too. (paranoid?) */ 285 1.2 gwr si->dma_addrh = 0; 286 1.2 gwr si->dma_addrl = 0; 287 1.2 gwr 288 1.2 gwr /* Finally, enable the DMA engine. */ 289 1.1 gwr si->si_csr |= SI_CSR_DMA_EN; 290 1.1 gwr } 291 1.1 gwr 292 1.1 gwr /* 293 1.1 gwr * This is called when the bus is idle and we are 294 1.1 gwr * about to start playing with the SBC chip. 295 1.1 gwr */ 296 1.33 tsutsui void 297 1.23 chs si_vme_intr_off(struct ncr5380_softc *ncr_sc) 298 1.1 gwr { 299 1.1 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 300 1.1 gwr volatile struct si_regs *si = sc->sc_regs; 301 1.1 gwr 302 1.1 gwr si->si_csr &= ~SI_CSR_DMA_EN; 303 1.1 gwr } 304 1.1 gwr 305 1.1 gwr /* 306 1.1 gwr * This function is called during the COMMAND or MSG_IN phase 307 1.16 wiz * that precedes a DATA_IN or DATA_OUT phase, in case we need 308 1.1 gwr * to setup the DMA engine before the bus enters a DATA phase. 309 1.1 gwr * 310 1.1 gwr * XXX: The VME adapter appears to suppress SBC interrupts 311 1.1 gwr * when the FIFO is not empty or the FIFO count is non-zero! 312 1.1 gwr * 313 1.31 andvar * On the VME version, setup the start address, but clear the 314 1.2 gwr * count (to make sure it stays idle) and set that later. 315 1.1 gwr */ 316 1.33 tsutsui void 317 1.23 chs si_vme_dma_setup(struct ncr5380_softc *ncr_sc) 318 1.1 gwr { 319 1.1 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 320 1.1 gwr struct sci_req *sr = ncr_sc->sc_current; 321 1.1 gwr struct si_dma_handle *dh = sr->sr_dma_hand; 322 1.1 gwr volatile struct si_regs *si = sc->sc_regs; 323 1.1 gwr long data_pa; 324 1.1 gwr int xlen; 325 1.1 gwr 326 1.1 gwr /* 327 1.1 gwr * Get the DVMA mapping for this segment. 328 1.1 gwr * XXX - Should separate allocation and mapin. 329 1.1 gwr */ 330 1.26 tsutsui data_pa = dh->dh_dmaaddr; 331 1.1 gwr if (data_pa & 1) 332 1.28 tsutsui panic("%s: bad pa=0x%lx", __func__, data_pa); 333 1.26 tsutsui xlen = dh->dh_dmalen; 334 1.2 gwr xlen &= ~1; /* XXX: necessary? */ 335 1.2 gwr sc->sc_reqlen = xlen; /* XXX: or less? */ 336 1.1 gwr 337 1.1 gwr #ifdef DEBUG 338 1.1 gwr if (si_debug & 2) { 339 1.28 tsutsui printf("%s: dh=%p, pa=0x%lx, xlen=0x%x\n", 340 1.28 tsutsui __func__, dh, data_pa, xlen); 341 1.1 gwr } 342 1.1 gwr #endif 343 1.1 gwr 344 1.1 gwr /* Set direction (send/recv) */ 345 1.1 gwr if (dh->dh_flags & SIDH_OUT) { 346 1.1 gwr si->si_csr |= SI_CSR_SEND; 347 1.1 gwr } else { 348 1.1 gwr si->si_csr &= ~SI_CSR_SEND; 349 1.1 gwr } 350 1.1 gwr 351 1.2 gwr /* Reset the FIFO. */ 352 1.2 gwr si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ 353 1.2 gwr si->si_csr |= SI_CSR_FIFO_RES; 354 1.2 gwr 355 1.1 gwr if (data_pa & 2) { 356 1.1 gwr si->si_csr |= SI_CSR_BPCON; 357 1.1 gwr } else { 358 1.1 gwr si->si_csr &= ~SI_CSR_BPCON; 359 1.1 gwr } 360 1.1 gwr 361 1.2 gwr /* Load the start address. */ 362 1.28 tsutsui si->dma_addrh = (uint16_t)(data_pa >> 16); 363 1.28 tsutsui si->dma_addrl = (uint16_t)(data_pa & 0xFFFF); 364 1.1 gwr 365 1.2 gwr /* 366 1.2 gwr * Keep the count zero or it may start early! 367 1.2 gwr */ 368 1.2 gwr si->dma_counth = 0; 369 1.2 gwr si->dma_countl = 0; 370 1.2 gwr 371 1.2 gwr #if 0 372 1.2 gwr /* Clear FIFO counter. (also hits dma_count) */ 373 1.2 gwr si->fifo_cnt_hi = 0; 374 1.2 gwr si->fifo_count = 0; 375 1.2 gwr #endif 376 1.2 gwr } 377 1.2 gwr 378 1.2 gwr 379 1.33 tsutsui void 380 1.23 chs si_vme_dma_start(struct ncr5380_softc *ncr_sc) 381 1.2 gwr { 382 1.2 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 383 1.2 gwr struct sci_req *sr = ncr_sc->sc_current; 384 1.2 gwr struct si_dma_handle *dh = sr->sr_dma_hand; 385 1.2 gwr volatile struct si_regs *si = sc->sc_regs; 386 1.2 gwr int s, xlen; 387 1.2 gwr 388 1.2 gwr xlen = sc->sc_reqlen; 389 1.2 gwr 390 1.2 gwr /* This MAY be time critical (not sure). */ 391 1.2 gwr s = splhigh(); 392 1.2 gwr 393 1.28 tsutsui si->dma_counth = (uint16_t)(xlen >> 16); 394 1.28 tsutsui si->dma_countl = (uint16_t)(xlen & 0xFFFF); 395 1.1 gwr 396 1.2 gwr /* Set it anyway, even though dma_count hits it. */ 397 1.28 tsutsui si->fifo_cnt_hi = (uint16_t)(xlen >> 16); 398 1.28 tsutsui si->fifo_count = (uint16_t)(xlen & 0xFFFF); 399 1.1 gwr 400 1.1 gwr /* 401 1.1 gwr * Acknowledge the phase change. (After DMA setup!) 402 1.1 gwr * Put the SBIC into DMA mode, and start the transfer. 403 1.1 gwr */ 404 1.1 gwr if (dh->dh_flags & SIDH_OUT) { 405 1.1 gwr *ncr_sc->sci_tcmd = PHASE_DATA_OUT; 406 1.1 gwr SCI_CLR_INTR(ncr_sc); 407 1.1 gwr *ncr_sc->sci_icmd = SCI_ICMD_DATA; 408 1.1 gwr *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); 409 1.1 gwr *ncr_sc->sci_dma_send = 0; /* start it */ 410 1.1 gwr } else { 411 1.1 gwr *ncr_sc->sci_tcmd = PHASE_DATA_IN; 412 1.1 gwr SCI_CLR_INTR(ncr_sc); 413 1.1 gwr *ncr_sc->sci_icmd = 0; 414 1.1 gwr *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); 415 1.1 gwr *ncr_sc->sci_irecv = 0; /* start it */ 416 1.1 gwr } 417 1.1 gwr 418 1.1 gwr /* Let'er rip! */ 419 1.1 gwr si->si_csr |= SI_CSR_DMA_EN; 420 1.1 gwr 421 1.2 gwr splx(s); 422 1.1 gwr ncr_sc->sc_state |= NCR_DOINGDMA; 423 1.1 gwr 424 1.1 gwr #ifdef DEBUG 425 1.1 gwr if (si_debug & 2) { 426 1.28 tsutsui printf("%s: started, flags=0x%x\n", 427 1.28 tsutsui __func__, ncr_sc->sc_state); 428 1.1 gwr } 429 1.1 gwr #endif 430 1.1 gwr } 431 1.1 gwr 432 1.1 gwr 433 1.33 tsutsui void 434 1.23 chs si_vme_dma_eop(struct ncr5380_softc *ncr_sc) 435 1.1 gwr { 436 1.1 gwr 437 1.1 gwr /* Not needed - DMA was stopped prior to examining sci_csr */ 438 1.1 gwr } 439 1.1 gwr 440 1.1 gwr 441 1.33 tsutsui void 442 1.23 chs si_vme_dma_stop(struct ncr5380_softc *ncr_sc) 443 1.1 gwr { 444 1.1 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 445 1.1 gwr struct sci_req *sr = ncr_sc->sc_current; 446 1.1 gwr struct si_dma_handle *dh = sr->sr_dma_hand; 447 1.1 gwr volatile struct si_regs *si = sc->sc_regs; 448 1.1 gwr int resid, ntrans; 449 1.1 gwr 450 1.1 gwr if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 451 1.1 gwr #ifdef DEBUG 452 1.28 tsutsui printf("%s: DMA not running\n", __func__); 453 1.1 gwr #endif 454 1.1 gwr return; 455 1.1 gwr } 456 1.1 gwr ncr_sc->sc_state &= ~NCR_DOINGDMA; 457 1.1 gwr 458 1.1 gwr /* First, halt the DMA engine. */ 459 1.1 gwr si->si_csr &= ~SI_CSR_DMA_EN; /* VME only */ 460 1.1 gwr 461 1.2 gwr /* Set an impossible phase to prevent data movement? */ 462 1.2 gwr *ncr_sc->sci_tcmd = PHASE_INVALID; 463 1.2 gwr 464 1.1 gwr if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { 465 1.4 christos printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); 466 1.1 gwr sr->sr_xs->error = XS_DRIVER_STUFFUP; 467 1.1 gwr ncr_sc->sc_state |= NCR_ABORTING; 468 1.13 gwr si_vme_reset(ncr_sc); 469 1.2 gwr goto out; 470 1.1 gwr } 471 1.1 gwr 472 1.1 gwr /* Note that timeout may have set the error flag. */ 473 1.1 gwr if (ncr_sc->sc_state & NCR_ABORTING) 474 1.1 gwr goto out; 475 1.2 gwr 476 1.2 gwr /* XXX: Wait for DMA to actually finish? */ 477 1.1 gwr 478 1.1 gwr /* 479 1.1 gwr * Now try to figure out how much actually transferred 480 1.1 gwr * 481 1.1 gwr * The fifo_count does not reflect how many bytes were 482 1.1 gwr * actually transferred for VME. 483 1.1 gwr * 484 1.1 gwr * SCSI-3 VME interface is a little funny on writes: 485 1.21 wiz * if we have a disconnect, the DMA has overshot by 486 1.1 gwr * one byte and the resid needs to be incremented. 487 1.1 gwr * Only happens for partial transfers. 488 1.1 gwr * (Thanks to Matt Jacob) 489 1.1 gwr */ 490 1.1 gwr 491 1.1 gwr resid = si->fifo_count & 0xFFFF; 492 1.1 gwr if (dh->dh_flags & SIDH_OUT) 493 1.1 gwr if ((resid > 0) && (resid < sc->sc_reqlen)) 494 1.1 gwr resid++; 495 1.1 gwr ntrans = sc->sc_reqlen - resid; 496 1.1 gwr 497 1.1 gwr #ifdef DEBUG 498 1.1 gwr if (si_debug & 2) { 499 1.28 tsutsui printf("%s: resid=0x%x ntrans=0x%x\n", 500 1.28 tsutsui __func__, resid, ntrans); 501 1.1 gwr } 502 1.1 gwr #endif 503 1.1 gwr 504 1.1 gwr if (ntrans < MIN_DMA_LEN) { 505 1.4 christos printf("si: fifo count: 0x%x\n", resid); 506 1.1 gwr ncr_sc->sc_state |= NCR_ABORTING; 507 1.1 gwr goto out; 508 1.1 gwr } 509 1.1 gwr if (ntrans > ncr_sc->sc_datalen) 510 1.28 tsutsui panic("%s: excess transfer", __func__); 511 1.1 gwr 512 1.1 gwr /* Adjust data pointer */ 513 1.1 gwr ncr_sc->sc_dataptr += ntrans; 514 1.1 gwr ncr_sc->sc_datalen -= ntrans; 515 1.1 gwr 516 1.1 gwr /* 517 1.1 gwr * After a read, we may need to clean-up 518 1.1 gwr * "Left-over bytes" (yuck!) 519 1.1 gwr */ 520 1.1 gwr if (((dh->dh_flags & SIDH_OUT) == 0) && 521 1.28 tsutsui ((si->si_csr & SI_CSR_LOB) != 0)) { 522 1.28 tsutsui uint8_t *cp = ncr_sc->sc_dataptr; 523 1.1 gwr #ifdef DEBUG 524 1.4 christos printf("si: Got Left-over bytes!\n"); 525 1.1 gwr #endif 526 1.1 gwr if (si->si_csr & SI_CSR_BPCON) { 527 1.1 gwr /* have SI_CSR_BPCON */ 528 1.1 gwr cp[-1] = (si->si_bprl & 0xff00) >> 8; 529 1.1 gwr } else { 530 1.1 gwr switch (si->si_csr & SI_CSR_LOB) { 531 1.1 gwr case SI_CSR_LOB_THREE: 532 1.1 gwr cp[-3] = (si->si_bprh & 0xff00) >> 8; 533 1.1 gwr cp[-2] = (si->si_bprh & 0x00ff); 534 1.1 gwr cp[-1] = (si->si_bprl & 0xff00) >> 8; 535 1.1 gwr break; 536 1.1 gwr case SI_CSR_LOB_TWO: 537 1.1 gwr cp[-2] = (si->si_bprh & 0xff00) >> 8; 538 1.1 gwr cp[-1] = (si->si_bprh & 0x00ff); 539 1.1 gwr break; 540 1.1 gwr case SI_CSR_LOB_ONE: 541 1.1 gwr cp[-1] = (si->si_bprh & 0xff00) >> 8; 542 1.1 gwr break; 543 1.1 gwr } 544 1.1 gwr } 545 1.1 gwr } 546 1.1 gwr 547 1.1 gwr out: 548 1.1 gwr si->dma_addrh = 0; 549 1.1 gwr si->dma_addrl = 0; 550 1.1 gwr 551 1.1 gwr si->dma_counth = 0; 552 1.1 gwr si->dma_countl = 0; 553 1.1 gwr 554 1.1 gwr si->fifo_cnt_hi = 0; 555 1.1 gwr si->fifo_count = 0; 556 1.1 gwr 557 1.1 gwr /* Put SBIC back in PIO mode. */ 558 1.1 gwr *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); 559 1.1 gwr *ncr_sc->sci_icmd = 0; 560 1.1 gwr } 561