1 1.65 tsutsui /* $NetBSD: si.c,v 1.65 2024/12/20 23:52:00 tsutsui Exp $ */ 2 1.8 cgd 3 1.31 gwr /*- 4 1.31 gwr * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 1.1 glass * All rights reserved. 6 1.1 glass * 7 1.31 gwr * This code is derived from software contributed to The NetBSD Foundation 8 1.31 gwr * by Adam Glass, David Jones, and Gordon W. Ross. 9 1.31 gwr * 10 1.1 glass * Redistribution and use in source and binary forms, with or without 11 1.1 glass * modification, are permitted provided that the following conditions 12 1.1 glass * are met: 13 1.1 glass * 1. Redistributions of source code must retain the above copyright 14 1.1 glass * notice, this list of conditions and the following disclaimer. 15 1.1 glass * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 glass * notice, this list of conditions and the following disclaimer in the 17 1.1 glass * documentation and/or other materials provided with the distribution. 18 1.1 glass * 19 1.31 gwr * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.31 gwr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.31 gwr * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.33 gwr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.33 gwr * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.31 gwr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.31 gwr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.31 gwr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.31 gwr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.31 gwr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.31 gwr * POSSIBILITY OF SUCH DAMAGE. 30 1.1 glass */ 31 1.1 glass 32 1.24 gwr /* 33 1.24 gwr * This file contains only the machine-dependent parts of the 34 1.24 gwr * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) 35 1.24 gwr * The machine-independent parts are in ncr5380sbc.c 36 1.24 gwr * 37 1.24 gwr * Supported hardware includes: 38 1.24 gwr * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) 39 1.24 gwr * Sun SCSI-3 on VME (Sun3/160,Sun3/260) 40 1.24 gwr * 41 1.24 gwr * Could be made to support the Sun3/E if someone wanted to. 42 1.24 gwr * 43 1.24 gwr * Note: Both supported variants of the Sun SCSI-3 adapter have 44 1.24 gwr * some really unusual "features" for this driver to deal with, 45 1.24 gwr * generally related to the DMA engine. The OBIO variant will 46 1.24 gwr * ignore any attempt to write the FIFO count register while the 47 1.24 gwr * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with 48 1.24 gwr * by setting the FIFO count early in COMMAND or MSG_IN phase. 49 1.24 gwr * 50 1.24 gwr * The VME variant has a bit to enable or disable the DMA engine, 51 1.24 gwr * but that bit also gates the interrupt line from the NCR5380! 52 1.24 gwr * Therefore, in order to get any interrupt from the 5380, (i.e. 53 1.24 gwr * for reselect) one must clear the DMA engine transfer count and 54 1.24 gwr * then enable DMA. This has the further complication that you 55 1.24 gwr * CAN NOT touch the NCR5380 while the DMA enable bit is set, so 56 1.24 gwr * we have to turn DMA back off before we even look at the 5380. 57 1.24 gwr * 58 1.24 gwr * What wonderfully whacky hardware this is! 59 1.24 gwr * 60 1.24 gwr * Credits, history: 61 1.24 gwr * 62 1.24 gwr * David Jones wrote the initial version of this module, which 63 1.24 gwr * included support for the VME adapter only. (no reselection). 64 1.24 gwr * 65 1.24 gwr * Gordon Ross added support for the OBIO adapter, and re-worked 66 1.24 gwr * both the VME and OBIO code to support disconnect/reselect. 67 1.24 gwr * (Required figuring out the hardware "features" noted above.) 68 1.24 gwr * 69 1.24 gwr * The autoconfiguration boilerplate came from Adam Glass. 70 1.24 gwr */ 71 1.54 lukem 72 1.54 lukem #include <sys/cdefs.h> 73 1.65 tsutsui __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.65 2024/12/20 23:52:00 tsutsui Exp $"); 74 1.1 glass 75 1.1 glass #include <sys/param.h> 76 1.1 glass #include <sys/systm.h> 77 1.1 glass #include <sys/errno.h> 78 1.24 gwr #include <sys/kernel.h> 79 1.64 thorpej #include <sys/kmem.h> 80 1.24 gwr #include <sys/device.h> 81 1.1 glass #include <sys/buf.h> 82 1.1 glass #include <sys/proc.h> 83 1.24 gwr 84 1.36 bouyer #include <dev/scsipi/scsi_all.h> 85 1.36 bouyer #include <dev/scsipi/scsipi_all.h> 86 1.36 bouyer #include <dev/scsipi/scsipi_debug.h> 87 1.36 bouyer #include <dev/scsipi/scsiconf.h> 88 1.1 glass 89 1.1 glass #include <machine/autoconf.h> 90 1.58 tsutsui #include <machine/bus.h> 91 1.24 gwr #include <machine/dvma.h> 92 1.1 glass 93 1.38 gwr /* #define DEBUG XXX */ 94 1.24 gwr 95 1.24 gwr #include <dev/ic/ncr5380reg.h> 96 1.24 gwr #include <dev/ic/ncr5380var.h> 97 1.2 gwr 98 1.24 gwr #include "sireg.h" 99 1.24 gwr #include "sivar.h" 100 1.14 gwr 101 1.30 gwr /* 102 1.30 gwr * Transfers smaller than this are done using PIO 103 1.30 gwr * (on assumption they're not worth DMA overhead) 104 1.30 gwr */ 105 1.30 gwr #define MIN_DMA_LEN 128 106 1.30 gwr 107 1.24 gwr int si_debug = 0; 108 1.14 gwr #ifdef DEBUG 109 1.14 gwr #endif 110 1.1 glass 111 1.24 gwr /* How long to wait for DMA before declaring an error. */ 112 1.24 gwr int si_dma_intr_timo = 500; /* ticks (sec. X 100) */ 113 1.1 glass 114 1.56 chs static void si_minphys(struct buf *); 115 1.1 glass 116 1.24 gwr /* 117 1.24 gwr * New-style autoconfig attachment. The cfattach 118 1.24 gwr * structures are in si_obio.c and si_vme.c 119 1.24 gwr */ 120 1.1 glass 121 1.65 tsutsui void 122 1.56 chs si_attach(struct si_softc *sc) 123 1.24 gwr { 124 1.61 tsutsui struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 125 1.24 gwr volatile struct si_regs *regs = sc->sc_regs; 126 1.24 gwr int i; 127 1.30 gwr 128 1.30 gwr /* 129 1.30 gwr * Support the "options" (config file flags). 130 1.34 gwr * Disconnect/reselect is a per-target mask. 131 1.34 gwr * Interrupts and DMA are per-controller. 132 1.30 gwr */ 133 1.34 gwr ncr_sc->sc_no_disconnect = 134 1.61 tsutsui (sc->sc_options & SI_NO_DISCONNECT); 135 1.65 tsutsui ncr_sc->sc_parity_disable = 136 1.61 tsutsui (sc->sc_options & SI_NO_PARITY_CHK) >> 8; 137 1.34 gwr if (sc->sc_options & SI_FORCE_POLLING) 138 1.30 gwr ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; 139 1.34 gwr 140 1.30 gwr #if 1 /* XXX - Temporary */ 141 1.30 gwr /* XXX - In case we think DMA is completely broken... */ 142 1.34 gwr if (sc->sc_options & SI_DISABLE_DMA) { 143 1.30 gwr /* Override this function pointer. */ 144 1.30 gwr ncr_sc->sc_dma_alloc = NULL; 145 1.30 gwr } 146 1.30 gwr #endif 147 1.30 gwr ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 148 1.16 gwr 149 1.24 gwr /* 150 1.24 gwr * Initialize fields used by the MI code 151 1.24 gwr */ 152 1.24 gwr ncr_sc->sci_r0 = ®s->sci.sci_r0; 153 1.24 gwr ncr_sc->sci_r1 = ®s->sci.sci_r1; 154 1.24 gwr ncr_sc->sci_r2 = ®s->sci.sci_r2; 155 1.24 gwr ncr_sc->sci_r3 = ®s->sci.sci_r3; 156 1.24 gwr ncr_sc->sci_r4 = ®s->sci.sci_r4; 157 1.24 gwr ncr_sc->sci_r5 = ®s->sci.sci_r5; 158 1.24 gwr ncr_sc->sci_r6 = ®s->sci.sci_r6; 159 1.24 gwr ncr_sc->sci_r7 = ®s->sci.sci_r7; 160 1.48 tsutsui 161 1.48 tsutsui ncr_sc->sc_rev = NCR_VARIANT_NCR5380; 162 1.12 gwr 163 1.24 gwr /* 164 1.24 gwr * Allocate DMA handles. 165 1.24 gwr */ 166 1.24 gwr i = SCI_OPENINGS * sizeof(struct si_dma_handle); 167 1.64 thorpej sc->sc_dma = kmem_alloc(i, KM_SLEEP); 168 1.24 gwr for (i = 0; i < SCI_OPENINGS; i++) 169 1.24 gwr sc->sc_dma[i].dh_flags = 0; 170 1.12 gwr 171 1.50 bouyer ncr_sc->sc_channel.chan_id = 7; 172 1.50 bouyer ncr_sc->sc_adapter.adapt_minphys = si_minphys; 173 1.47 mycroft 174 1.12 gwr /* 175 1.24 gwr * Initialize si board itself. 176 1.12 gwr */ 177 1.47 mycroft ncr5380_attach(ncr_sc); 178 1.1 glass } 179 1.1 glass 180 1.24 gwr static void 181 1.24 gwr si_minphys(struct buf *bp) 182 1.1 glass { 183 1.61 tsutsui 184 1.24 gwr if (bp->b_bcount > MAX_DMA_LEN) { 185 1.14 gwr #ifdef DEBUG 186 1.24 gwr if (si_debug) { 187 1.61 tsutsui printf("%s len = 0x%x.\n", __func__, bp->b_bcount); 188 1.24 gwr Debugger(); 189 1.1 glass } 190 1.24 gwr #endif 191 1.24 gwr bp->b_bcount = MAX_DMA_LEN; 192 1.1 glass } 193 1.52 kristerw minphys(bp); 194 1.1 glass } 195 1.1 glass 196 1.1 glass 197 1.24 gwr #define CSR_WANT (SI_CSR_SBC_IP | SI_CSR_DMA_IP | \ 198 1.24 gwr SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR ) 199 1.24 gwr 200 1.24 gwr int 201 1.24 gwr si_intr(void *arg) 202 1.1 glass { 203 1.24 gwr struct si_softc *sc = arg; 204 1.24 gwr volatile struct si_regs *si = sc->sc_regs; 205 1.24 gwr int dma_error, claimed; 206 1.24 gwr u_short csr; 207 1.1 glass 208 1.24 gwr claimed = 0; 209 1.24 gwr dma_error = 0; 210 1.24 gwr 211 1.24 gwr /* SBC interrupt? DMA interrupt? */ 212 1.24 gwr csr = si->si_csr; 213 1.24 gwr NCR_TRACE("si_intr: csr=0x%x\n", csr); 214 1.24 gwr 215 1.24 gwr if (csr & SI_CSR_DMA_CONFLICT) { 216 1.24 gwr dma_error |= SI_CSR_DMA_CONFLICT; 217 1.61 tsutsui printf("%s: DMA conflict\n", __func__); 218 1.24 gwr } 219 1.24 gwr if (csr & SI_CSR_DMA_BUS_ERR) { 220 1.24 gwr dma_error |= SI_CSR_DMA_BUS_ERR; 221 1.61 tsutsui printf("%s: DMA bus error\n", __func__); 222 1.24 gwr } 223 1.24 gwr if (dma_error) { 224 1.24 gwr if (sc->ncr_sc.sc_state & NCR_DOINGDMA) 225 1.24 gwr sc->ncr_sc.sc_state |= NCR_ABORTING; 226 1.24 gwr /* Make sure we will call the main isr. */ 227 1.24 gwr csr |= SI_CSR_DMA_IP; 228 1.24 gwr } 229 1.24 gwr 230 1.24 gwr if (csr & (SI_CSR_SBC_IP | SI_CSR_DMA_IP)) { 231 1.24 gwr claimed = ncr5380_intr(&sc->ncr_sc); 232 1.24 gwr #ifdef DEBUG 233 1.24 gwr if (!claimed) { 234 1.61 tsutsui printf("%s: spurious from SBC\n", __func__); 235 1.44 jdolecek if (si_debug & 4) 236 1.24 gwr Debugger(); /* XXX */ 237 1.24 gwr } 238 1.2 gwr #endif 239 1.35 gwr /* Yes, we DID cause this interrupt. */ 240 1.35 gwr claimed = 1; 241 1.10 gwr } 242 1.14 gwr 243 1.61 tsutsui return claimed; 244 1.1 glass } 245 1.1 glass 246 1.14 gwr 247 1.24 gwr /***************************************************************** 248 1.24 gwr * Common functions for DMA 249 1.24 gwr ****************************************************************/ 250 1.1 glass 251 1.24 gwr /* 252 1.24 gwr * Allocate a DMA handle and put it in sc->sc_dma. Prepare 253 1.24 gwr * for DMA transfer. On the Sun3, this means mapping the buffer 254 1.24 gwr * into DVMA space. dvma_mapin() flushes the cache for us. 255 1.24 gwr */ 256 1.65 tsutsui void 257 1.56 chs si_dma_alloc(struct ncr5380_softc *ncr_sc) 258 1.24 gwr { 259 1.24 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 260 1.24 gwr struct sci_req *sr = ncr_sc->sc_current; 261 1.36 bouyer struct scsipi_xfer *xs = sr->sr_xs; 262 1.24 gwr struct si_dma_handle *dh; 263 1.24 gwr int i, xlen; 264 1.58 tsutsui void *addr; 265 1.1 glass 266 1.14 gwr #ifdef DIAGNOSTIC 267 1.24 gwr if (sr->sr_dma_hand != NULL) 268 1.61 tsutsui panic("%s: already have DMA handle", __func__); 269 1.14 gwr #endif 270 1.14 gwr 271 1.58 tsutsui addr = ncr_sc->sc_dataptr; 272 1.24 gwr xlen = ncr_sc->sc_datalen; 273 1.13 gwr 274 1.24 gwr /* If the DMA start addr is misaligned then do PIO */ 275 1.58 tsutsui if (((vaddr_t)addr & 1) || (xlen & 1)) { 276 1.61 tsutsui printf("%s: misaligned.\n", __func__); 277 1.24 gwr return; 278 1.1 glass } 279 1.1 glass 280 1.24 gwr /* Make sure our caller checked sc_min_dma_len. */ 281 1.24 gwr if (xlen < MIN_DMA_LEN) 282 1.61 tsutsui panic("%s: xlen=0x%x", __func__, xlen); 283 1.14 gwr 284 1.24 gwr /* 285 1.24 gwr * Never attempt single transfers of more than 63k, because 286 1.24 gwr * our count register may be only 16 bits (an OBIO adapter). 287 1.24 gwr * This should never happen since already bounded by minphys(). 288 1.24 gwr * XXX - Should just segment these... 289 1.24 gwr */ 290 1.24 gwr if (xlen > MAX_DMA_LEN) { 291 1.61 tsutsui printf("%s: excessive xlen=0x%x\n", __func__, xlen); 292 1.24 gwr Debugger(); 293 1.24 gwr ncr_sc->sc_datalen = xlen = MAX_DMA_LEN; 294 1.24 gwr } 295 1.24 gwr 296 1.24 gwr /* Find free DMA handle. Guaranteed to find one since we have 297 1.24 gwr as many DMA handles as the driver has processes. */ 298 1.24 gwr for (i = 0; i < SCI_OPENINGS; i++) { 299 1.24 gwr if ((sc->sc_dma[i].dh_flags & SIDH_BUSY) == 0) 300 1.24 gwr goto found; 301 1.24 gwr } 302 1.24 gwr panic("si: no free DMA handles."); 303 1.24 gwr found: 304 1.24 gwr 305 1.24 gwr dh = &sc->sc_dma[i]; 306 1.24 gwr dh->dh_flags = SIDH_BUSY; 307 1.58 tsutsui 308 1.58 tsutsui if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, addr, xlen, NULL, 309 1.58 tsutsui BUS_DMA_NOWAIT) != 0) 310 1.61 tsutsui panic("%s: can't load dmamap", device_xname(ncr_sc->sc_dev)); 311 1.59 tsutsui dh->dh_dmaaddr = sc->sc_dmap->dm_segs[0].ds_addr; 312 1.58 tsutsui dh->dh_dmalen = xlen; 313 1.24 gwr 314 1.24 gwr /* Copy the "write" flag for convenience. */ 315 1.45 jdolecek if (xs->xs_control & XS_CTL_DATA_OUT) 316 1.24 gwr dh->dh_flags |= SIDH_OUT; 317 1.17 gwr 318 1.58 tsutsui bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, dh->dh_dmalen, 319 1.58 tsutsui (dh->dh_flags & SIDH_OUT) == 0 ? 320 1.58 tsutsui BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 321 1.58 tsutsui 322 1.24 gwr #if 0 323 1.24 gwr /* 324 1.24 gwr * Some machines might not need to remap B_PHYS buffers. 325 1.24 gwr * The sun3 does not map B_PHYS buffers into DVMA space, 326 1.24 gwr * (they are mapped into normal KV space) so on the sun3 327 1.24 gwr * we must always remap to a DVMA address here. Re-map is 328 1.24 gwr * cheap anyway, because it's done by segments, not pages. 329 1.24 gwr */ 330 1.24 gwr if (xs->bp && (xs->bp->b_flags & B_PHYS)) 331 1.24 gwr dh->dh_flags |= SIDH_PHYS; 332 1.14 gwr #endif 333 1.17 gwr 334 1.24 gwr /* success */ 335 1.24 gwr sr->sr_dma_hand = dh; 336 1.1 glass 337 1.24 gwr return; 338 1.1 glass } 339 1.1 glass 340 1.1 glass 341 1.65 tsutsui void 342 1.56 chs si_dma_free(struct ncr5380_softc *ncr_sc) 343 1.1 glass { 344 1.58 tsutsui struct si_softc *sc = (struct si_softc *)ncr_sc; 345 1.24 gwr struct sci_req *sr = ncr_sc->sc_current; 346 1.24 gwr struct si_dma_handle *dh = sr->sr_dma_hand; 347 1.1 glass 348 1.24 gwr #ifdef DIAGNOSTIC 349 1.24 gwr if (dh == NULL) 350 1.61 tsutsui panic("%s: no DMA handle", __func__); 351 1.24 gwr #endif 352 1.1 glass 353 1.24 gwr if (ncr_sc->sc_state & NCR_DOINGDMA) 354 1.61 tsutsui panic("%s: free while in progress", __func__); 355 1.1 glass 356 1.24 gwr if (dh->dh_flags & SIDH_BUSY) { 357 1.58 tsutsui bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, dh->dh_dmalen, 358 1.58 tsutsui (dh->dh_flags & SIDH_OUT) == 0 ? 359 1.58 tsutsui BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 360 1.58 tsutsui bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap); 361 1.58 tsutsui dh->dh_dmaaddr = 0; 362 1.24 gwr dh->dh_flags = 0; 363 1.1 glass } 364 1.24 gwr sr->sr_dma_hand = NULL; 365 1.1 glass } 366 1.1 glass 367 1.1 glass 368 1.25 gwr #define CSR_MASK (SI_CSR_SBC_IP | SI_CSR_DMA_IP | \ 369 1.25 gwr SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR) 370 1.25 gwr #define POLL_TIMO 50000 /* X100 = 5 sec. */ 371 1.25 gwr 372 1.24 gwr /* 373 1.24 gwr * Poll (spin-wait) for DMA completion. 374 1.24 gwr * Called right after xx_dma_start(), and 375 1.24 gwr * xx_dma_stop() will be called next. 376 1.24 gwr * Same for either VME or OBIO. 377 1.24 gwr */ 378 1.65 tsutsui void 379 1.56 chs si_dma_poll(struct ncr5380_softc *ncr_sc) 380 1.24 gwr { 381 1.24 gwr struct si_softc *sc = (struct si_softc *)ncr_sc; 382 1.24 gwr struct sci_req *sr = ncr_sc->sc_current; 383 1.24 gwr volatile struct si_regs *si = sc->sc_regs; 384 1.25 gwr int tmo; 385 1.1 glass 386 1.24 gwr /* Make sure DMA started successfully. */ 387 1.24 gwr if (ncr_sc->sc_state & NCR_ABORTING) 388 1.24 gwr return; 389 1.1 glass 390 1.25 gwr /* 391 1.25 gwr * XXX: The Sun driver waits for ~SI_CSR_DMA_ACTIVE here 392 1.25 gwr * XXX: (on obio) or even worse (on vme) a 10mS. delay! 393 1.25 gwr * XXX: I really doubt that is necessary... 394 1.25 gwr */ 395 1.1 glass 396 1.53 wiz /* Wait for any "DMA complete" or error bits. */ 397 1.25 gwr tmo = POLL_TIMO; 398 1.24 gwr for (;;) { 399 1.25 gwr if (si->si_csr & CSR_MASK) 400 1.24 gwr break; 401 1.24 gwr if (--tmo <= 0) { 402 1.29 christos printf("si: DMA timeout (while polling)\n"); 403 1.24 gwr /* Indicate timeout as MI code would. */ 404 1.24 gwr sr->sr_flags |= SR_OVERDUE; 405 1.24 gwr break; 406 1.1 glass } 407 1.24 gwr delay(100); 408 1.1 glass } 409 1.25 gwr NCR_TRACE("si_dma_poll: waited %d\n", 410 1.25 gwr POLL_TIMO - tmo); 411 1.1 glass 412 1.17 gwr #ifdef DEBUG 413 1.25 gwr if (si_debug & 2) { 414 1.61 tsutsui printf("%s: done, csr=0x%x\n", __func__, si->si_csr); 415 1.17 gwr } 416 1.17 gwr #endif 417 1.1 glass } 418