1 /* $NetBSD: ncr.c,v 1.39 2002/10/02 16:02:37 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * This file contains the machine-dependent parts of the NCR-5380 41 * controller. The machine-independent parts are in ncr5380sbc.c. 42 * 43 * Jens A. Nilsson. 44 * 45 * Credits: 46 * 47 * This code is based on arch/sun3/dev/si* 48 * Written by David Jones, Gordon Ross, and Adam Glass. 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/errno.h> 54 #include <sys/kernel.h> 55 #include <sys/malloc.h> 56 #include <sys/device.h> 57 #include <sys/buf.h> 58 #include <sys/proc.h> 59 #include <sys/user.h> 60 61 #include <dev/scsipi/scsi_all.h> 62 #include <dev/scsipi/scsipi_all.h> 63 #include <dev/scsipi/scsipi_debug.h> 64 #include <dev/scsipi/scsiconf.h> 65 66 #include <dev/ic/ncr5380reg.h> 67 #include <dev/ic/ncr5380var.h> 68 69 #include <machine/cpu.h> 70 #include <machine/vsbus.h> 71 #include <machine/bus.h> 72 #include <machine/sid.h> 73 #include <machine/scb.h> 74 #include <machine/clock.h> 75 76 #include "ioconf.h" 77 78 #define MIN_DMA_LEN 128 79 80 struct si_dma_handle { 81 int dh_flags; 82 #define SIDH_BUSY 1 83 #define SIDH_OUT 2 84 caddr_t dh_addr; 85 int dh_len; 86 struct proc *dh_proc; 87 }; 88 89 struct si_softc { 90 struct ncr5380_softc ncr_sc; 91 struct evcnt ncr_intrcnt; 92 caddr_t ncr_addr; 93 int ncr_off; 94 int ncr_dmaaddr; 95 int ncr_dmacount; 96 int ncr_dmadir; 97 struct si_dma_handle ncr_dma[SCI_OPENINGS]; 98 struct vsbus_dma sc_vd; 99 int onlyscsi; /* This machine needs no queueing */ 100 }; 101 102 static int ncr_dmasize; 103 104 static int si_vsbus_match(struct device *, struct cfdata *, void *); 105 static void si_vsbus_attach(struct device *, struct device *, void *); 106 static void si_minphys(struct buf *); 107 108 static void si_dma_alloc(struct ncr5380_softc *); 109 static void si_dma_free(struct ncr5380_softc *); 110 static void si_dma_setup(struct ncr5380_softc *); 111 static void si_dma_start(struct ncr5380_softc *); 112 static void si_dma_poll(struct ncr5380_softc *); 113 static void si_dma_eop(struct ncr5380_softc *); 114 static void si_dma_stop(struct ncr5380_softc *); 115 static void si_dma_go(void *); 116 117 CFATTACH_DECL(si_vsbus, sizeof(struct si_softc), 118 si_vsbus_match, si_vsbus_attach, NULL, NULL); 119 120 static int 121 si_vsbus_match(struct device *parent, struct cfdata *cf, void *aux) 122 { 123 struct vsbus_attach_args *va = aux; 124 volatile char *si_csr = (char *) va->va_addr; 125 126 if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46 127 || vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_53) 128 return 0; 129 /* This is the way Linux autoprobes the interrupt MK-990321 */ 130 si_csr[12] = 0; 131 si_csr[16] = 0x80; 132 si_csr[0] = 0x80; 133 si_csr[4] = 5; /* 0xcf */ 134 DELAY(100000); 135 return 1; 136 } 137 138 static void 139 si_vsbus_attach(struct device *parent, struct device *self, void *aux) 140 { 141 struct vsbus_attach_args *va = aux; 142 struct si_softc *sc = (struct si_softc *) self; 143 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 144 int tweak, target; 145 146 scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr5380_intr, sc, 147 SCB_ISTACK, &sc->ncr_intrcnt); 148 evcnt_attach_dynamic(&sc->ncr_intrcnt, EVCNT_TYPE_INTR, NULL, 149 self->dv_xname, "intr"); 150 151 /* 152 * DMA area mapin. 153 * On VS3100, split the 128K block between the two devices. 154 * On VS2000, don't care for now. 155 */ 156 #define DMASIZE (64*1024) 157 if (va->va_paddr & 0x100) { /* Secondary SCSI controller */ 158 sc->ncr_off = DMASIZE; 159 sc->onlyscsi = 1; 160 } 161 sc->ncr_addr = (caddr_t)va->va_dmaaddr; 162 ncr_dmasize = min(va->va_dmasize, MAXPHYS); 163 164 /* 165 * MD function pointers used by the MI code. 166 */ 167 ncr_sc->sc_dma_alloc = si_dma_alloc; 168 ncr_sc->sc_dma_free = si_dma_free; 169 ncr_sc->sc_dma_setup = si_dma_setup; 170 ncr_sc->sc_dma_start = si_dma_start; 171 ncr_sc->sc_dma_poll = si_dma_poll; 172 ncr_sc->sc_dma_eop = si_dma_eop; 173 ncr_sc->sc_dma_stop = si_dma_stop; 174 175 /* DMA control register offsets */ 176 sc->ncr_dmaaddr = 32; /* DMA address in buffer, longword */ 177 sc->ncr_dmacount = 64; /* DMA count register */ 178 sc->ncr_dmadir = 68; /* Direction of DMA transfer */ 179 180 ncr_sc->sc_pio_out = ncr5380_pio_out; 181 ncr_sc->sc_pio_in = ncr5380_pio_in; 182 183 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 184 185 /* 186 * Initialize fields used by the MI code. 187 */ 188 /* ncr_sc->sc_regt = Unused on VAX */ 189 ncr_sc->sc_regh = vax_map_physmem(va->va_paddr, 1); 190 191 /* Register offsets */ 192 ncr_sc->sci_r0 = 0; 193 ncr_sc->sci_r1 = 4; 194 ncr_sc->sci_r2 = 8; 195 ncr_sc->sci_r3 = 12; 196 ncr_sc->sci_r4 = 16; 197 ncr_sc->sci_r5 = 20; 198 ncr_sc->sci_r6 = 24; 199 ncr_sc->sci_r7 = 28; 200 201 ncr_sc->sc_rev = NCR_VARIANT_NCR5380; 202 203 ncr_sc->sc_no_disconnect = 0xff; 204 205 /* 206 * Get the SCSI chip target address out of NVRAM. 207 * This do not apply to the VS2000. 208 */ 209 tweak = clk_tweak + (va->va_paddr & 0x100 ? 3 : 0); 210 if (vax_boardtype == VAX_BTYP_410) 211 target = 7; 212 else 213 target = (clk_page[0xbc/2] >> tweak) & 7; 214 215 printf("\n%s: NCR5380, SCSI ID %d\n", ncr_sc->sc_dev.dv_xname, target); 216 217 ncr_sc->sc_adapter.adapt_minphys = si_minphys; 218 ncr_sc->sc_channel.chan_id = target; 219 220 /* 221 * Init the vsbus DMA resource queue struct */ 222 sc->sc_vd.vd_go = si_dma_go; 223 sc->sc_vd.vd_arg = sc; 224 225 /* 226 * Initialize si board itself. 227 */ 228 ncr5380_attach(ncr_sc); 229 } 230 231 /* 232 * Adjust the max transfer size. The DMA buffer is only 16k on VS2000. 233 */ 234 static void 235 si_minphys(struct buf *bp) 236 { 237 if (bp->b_bcount > ncr_dmasize) 238 bp->b_bcount = ncr_dmasize; 239 } 240 241 void 242 si_dma_alloc(struct ncr5380_softc *ncr_sc) 243 { 244 struct si_softc *sc = (struct si_softc *)ncr_sc; 245 struct sci_req *sr = ncr_sc->sc_current; 246 struct scsipi_xfer *xs = sr->sr_xs; 247 struct si_dma_handle *dh; 248 int xlen, i; 249 250 #ifdef DIAGNOSTIC 251 if (sr->sr_dma_hand != NULL) 252 panic("si_dma_alloc: already have DMA handle"); 253 #endif 254 255 /* Polled transfers shouldn't allocate a DMA handle. */ 256 if (sr->sr_flags & SR_IMMED) 257 return; 258 259 xlen = ncr_sc->sc_datalen; 260 261 /* Make sure our caller checked sc_min_dma_len. */ 262 if (xlen < MIN_DMA_LEN) 263 panic("si_dma_alloc: len=0x%x", xlen); 264 265 /* 266 * Find free PDMA handle. Guaranteed to find one since we 267 * have as many PDMA handles as the driver has processes. 268 * (instances?) 269 */ 270 for (i = 0; i < SCI_OPENINGS; i++) { 271 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 272 goto found; 273 } 274 panic("sbc: no free PDMA handles"); 275 found: 276 dh = &sc->ncr_dma[i]; 277 dh->dh_flags = SIDH_BUSY; 278 dh->dh_addr = ncr_sc->sc_dataptr; 279 dh->dh_len = xlen; 280 dh->dh_proc = xs->bp->b_proc; 281 282 /* Remember dest buffer parameters */ 283 if (xs->xs_control & XS_CTL_DATA_OUT) 284 dh->dh_flags |= SIDH_OUT; 285 286 sr->sr_dma_hand = dh; 287 } 288 289 void 290 si_dma_free(struct ncr5380_softc *ncr_sc) 291 { 292 struct sci_req *sr = ncr_sc->sc_current; 293 struct si_dma_handle *dh = sr->sr_dma_hand; 294 295 if (dh->dh_flags & SIDH_BUSY) 296 dh->dh_flags = 0; 297 else 298 printf("si_dma_free: free'ing unused buffer\n"); 299 300 sr->sr_dma_hand = NULL; 301 } 302 303 void 304 si_dma_setup(struct ncr5380_softc *ncr_sc) 305 { 306 /* Do nothing here */ 307 } 308 309 void 310 si_dma_start(struct ncr5380_softc *ncr_sc) 311 { 312 struct si_softc *sc = (struct si_softc *)ncr_sc; 313 314 /* Just put on queue; will call go() from below */ 315 if (sc->onlyscsi) 316 si_dma_go(ncr_sc); 317 else 318 vsbus_dma_start(&sc->sc_vd); 319 } 320 321 /* 322 * go() routine called when another transfer somewhere is finished. 323 */ 324 void 325 si_dma_go(void *arg) 326 { 327 struct ncr5380_softc *ncr_sc = arg; 328 struct si_softc *sc = (struct si_softc *)ncr_sc; 329 struct sci_req *sr = ncr_sc->sc_current; 330 struct si_dma_handle *dh = sr->sr_dma_hand; 331 332 /* 333 * Set the VAX-DMA-specific registers, and copy the data if 334 * it is directed "outbound". 335 */ 336 if (dh->dh_flags & SIDH_OUT) { 337 vsbus_copyfromproc(dh->dh_proc, dh->dh_addr, 338 sc->ncr_addr + sc->ncr_off, dh->dh_len); 339 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 340 sc->ncr_dmadir, 0); 341 } else { 342 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 343 sc->ncr_dmadir, 1); 344 } 345 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 346 sc->ncr_dmacount, -dh->dh_len); 347 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 348 sc->ncr_dmaaddr, sc->ncr_off); 349 /* 350 * Now from the 5380-internal DMA registers. 351 */ 352 if (dh->dh_flags & SIDH_OUT) { 353 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 354 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 355 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 356 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 357 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 358 } else { 359 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 360 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 361 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 362 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 363 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 364 } 365 ncr_sc->sc_state |= NCR_DOINGDMA; 366 } 367 368 /* 369 * When? 370 */ 371 void 372 si_dma_poll(struct ncr5380_softc *ncr_sc) 373 { 374 printf("si_dma_poll\n"); 375 } 376 377 /* 378 * When? 379 */ 380 void 381 si_dma_eop(struct ncr5380_softc *ncr_sc) 382 { 383 printf("si_dma_eop\n"); 384 } 385 386 void 387 si_dma_stop(struct ncr5380_softc *ncr_sc) 388 { 389 struct si_softc *sc = (struct si_softc *)ncr_sc; 390 struct sci_req *sr = ncr_sc->sc_current; 391 struct si_dma_handle *dh = sr->sr_dma_hand; 392 int count, i; 393 394 if (ncr_sc->sc_state & NCR_DOINGDMA) 395 ncr_sc->sc_state &= ~NCR_DOINGDMA; 396 397 /* 398 * Sometimes the FIFO buffer isn't drained when the 399 * interrupt is posted. Just loop here and hope that 400 * it will drain soon. 401 */ 402 for (i = 0; i < 20000; i++) { 403 count = bus_space_read_4(ncr_sc->sc_regt, 404 ncr_sc->sc_regh, sc->ncr_dmacount); 405 if (count == 0) 406 break; 407 DELAY(100); 408 } 409 if (count == 0) { 410 if (((dh->dh_flags & SIDH_OUT) == 0)) { 411 vsbus_copytoproc(dh->dh_proc, 412 sc->ncr_addr + sc->ncr_off, 413 dh->dh_addr, dh->dh_len); 414 } 415 ncr_sc->sc_dataptr += dh->dh_len; 416 ncr_sc->sc_datalen -= dh->dh_len; 417 } 418 419 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 420 ~(SCI_MODE_DMA | SCI_MODE_DMA_IE)); 421 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 422 if (sc->onlyscsi == 0) 423 vsbus_dma_intr(); /* Try to start more transfers */ 424 } 425