1 /* $NetBSD: ncr.c,v 1.35 2001/04/25 17:53:26 bouyer 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 struct cfattach si_vsbus_ca = { 118 sizeof(struct si_softc), si_vsbus_match, si_vsbus_attach 119 }; 120 121 static int 122 si_vsbus_match(struct device *parent, struct cfdata *cf, void *aux) 123 { 124 struct vsbus_attach_args *va = aux; 125 volatile char *si_csr = (char *) va->va_addr; 126 127 if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46 128 || vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_53) 129 return 0; 130 /* This is the way Linux autoprobes the interrupt MK-990321 */ 131 si_csr[12] = 0; 132 si_csr[16] = 0x80; 133 si_csr[0] = 0x80; 134 si_csr[4] = 5; /* 0xcf */ 135 DELAY(100000); 136 return 1; 137 } 138 139 static void 140 si_vsbus_attach(struct device *parent, struct device *self, void *aux) 141 { 142 struct vsbus_attach_args *va = aux; 143 struct si_softc *sc = (struct si_softc *) self; 144 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 145 int tweak, target; 146 147 scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr5380_intr, sc, 148 SCB_ISTACK, &sc->ncr_intrcnt); 149 evcnt_attach_dynamic(&sc->ncr_intrcnt, EVCNT_TYPE_INTR, NULL, 150 self->dv_xname, "intr"); 151 152 /* 153 * DMA area mapin. 154 * On VS3100, split the 128K block between the two devices. 155 * On VS2000, don't care for now. 156 */ 157 #define DMASIZE (64*1024) 158 if (va->va_paddr & 0x100) { /* Secondary SCSI controller */ 159 sc->ncr_off = DMASIZE; 160 sc->onlyscsi = 1; 161 } 162 sc->ncr_addr = (caddr_t)va->va_dmaaddr; 163 ncr_dmasize = min(va->va_dmasize, MAXPHYS); 164 165 /* 166 * MD function pointers used by the MI code. 167 */ 168 ncr_sc->sc_dma_alloc = si_dma_alloc; 169 ncr_sc->sc_dma_free = si_dma_free; 170 ncr_sc->sc_dma_setup = si_dma_setup; 171 ncr_sc->sc_dma_start = si_dma_start; 172 ncr_sc->sc_dma_poll = si_dma_poll; 173 ncr_sc->sc_dma_eop = si_dma_eop; 174 ncr_sc->sc_dma_stop = si_dma_stop; 175 176 /* DMA control register offsets */ 177 sc->ncr_dmaaddr = 32; /* DMA address in buffer, longword */ 178 sc->ncr_dmacount = 64; /* DMA count register */ 179 sc->ncr_dmadir = 68; /* Direction of DMA transfer */ 180 181 ncr_sc->sc_pio_out = ncr5380_pio_out; 182 ncr_sc->sc_pio_in = ncr5380_pio_in; 183 184 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 185 186 /* 187 * Initialize fields used by the MI code. 188 */ 189 /* ncr_sc->sc_regt = Unused on VAX */ 190 ncr_sc->sc_regh = vax_map_physmem(va->va_paddr, 1); 191 192 /* Register offsets */ 193 ncr_sc->sci_r0 = 0; 194 ncr_sc->sci_r1 = 4; 195 ncr_sc->sci_r2 = 8; 196 ncr_sc->sci_r3 = 12; 197 ncr_sc->sci_r4 = 16; 198 ncr_sc->sci_r5 = 20; 199 ncr_sc->sci_r6 = 24; 200 ncr_sc->sci_r7 = 28; 201 202 ncr_sc->sc_rev = NCR_VARIANT_NCR5380; 203 204 ncr_sc->sc_no_disconnect = 0xff; 205 206 /* 207 * Get the SCSI chip target address out of NVRAM. 208 * This do not apply to the VS2000. 209 */ 210 tweak = clk_tweak + (va->va_paddr & 0x100 ? 3 : 0); 211 if (vax_boardtype == VAX_BTYP_410) 212 target = 7; 213 else 214 target = (clk_page[0xbc/2] >> tweak) & 7; 215 216 printf("\n%s: NCR5380, SCSI ID %d\n", ncr_sc->sc_dev.dv_xname, target); 217 218 ncr_sc->sc_adapter.adapt_minphys = si_minphys; 219 ncr_sc->sc_channel.chan_id = target; 220 221 /* 222 * Init the vsbus DMA resource queue struct */ 223 sc->sc_vd.vd_go = si_dma_go; 224 sc->sc_vd.vd_arg = sc; 225 226 /* 227 * Initialize si board itself. 228 */ 229 ncr5380_attach(ncr_sc); 230 } 231 232 /* 233 * Adjust the max transfer size. The DMA buffer is only 16k on VS2000. 234 */ 235 static void 236 si_minphys(struct buf *bp) 237 { 238 if (bp->b_bcount > ncr_dmasize) 239 bp->b_bcount = ncr_dmasize; 240 } 241 242 void 243 si_dma_alloc(struct ncr5380_softc *ncr_sc) 244 { 245 struct si_softc *sc = (struct si_softc *)ncr_sc; 246 struct sci_req *sr = ncr_sc->sc_current; 247 struct scsipi_xfer *xs = sr->sr_xs; 248 struct si_dma_handle *dh; 249 int xlen, i; 250 251 #ifdef DIAGNOSTIC 252 if (sr->sr_dma_hand != NULL) 253 panic("si_dma_alloc: already have DMA handle"); 254 #endif 255 256 /* Polled transfers shouldn't allocate a DMA handle. */ 257 if (sr->sr_flags & SR_IMMED) 258 return; 259 260 xlen = ncr_sc->sc_datalen; 261 262 /* Make sure our caller checked sc_min_dma_len. */ 263 if (xlen < MIN_DMA_LEN) 264 panic("si_dma_alloc: len=0x%x\n", xlen); 265 266 /* 267 * Find free PDMA handle. Guaranteed to find one since we 268 * have as many PDMA handles as the driver has processes. 269 * (instances?) 270 */ 271 for (i = 0; i < SCI_OPENINGS; i++) { 272 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 273 goto found; 274 } 275 panic("sbc: no free PDMA handles"); 276 found: 277 dh = &sc->ncr_dma[i]; 278 dh->dh_flags = SIDH_BUSY; 279 dh->dh_addr = ncr_sc->sc_dataptr; 280 dh->dh_len = xlen; 281 dh->dh_proc = xs->bp->b_proc; 282 283 /* Remember dest buffer parameters */ 284 if (xs->xs_control & XS_CTL_DATA_OUT) 285 dh->dh_flags |= SIDH_OUT; 286 287 sr->sr_dma_hand = dh; 288 } 289 290 void 291 si_dma_free(struct ncr5380_softc *ncr_sc) 292 { 293 struct sci_req *sr = ncr_sc->sc_current; 294 struct si_dma_handle *dh = sr->sr_dma_hand; 295 296 if (dh->dh_flags & SIDH_BUSY) 297 dh->dh_flags = 0; 298 else 299 printf("si_dma_free: free'ing unused buffer\n"); 300 301 sr->sr_dma_hand = NULL; 302 } 303 304 void 305 si_dma_setup(struct ncr5380_softc *ncr_sc) 306 { 307 /* Do nothing here */ 308 } 309 310 void 311 si_dma_start(struct ncr5380_softc *ncr_sc) 312 { 313 struct si_softc *sc = (struct si_softc *)ncr_sc; 314 315 /* Just put on queue; will call go() from below */ 316 if (sc->onlyscsi) 317 si_dma_go(ncr_sc); 318 else 319 vsbus_dma_start(&sc->sc_vd); 320 } 321 322 /* 323 * go() routine called when another transfer somewhere is finished. 324 */ 325 void 326 si_dma_go(void *arg) 327 { 328 struct ncr5380_softc *ncr_sc = arg; 329 struct si_softc *sc = (struct si_softc *)ncr_sc; 330 struct sci_req *sr = ncr_sc->sc_current; 331 struct si_dma_handle *dh = sr->sr_dma_hand; 332 333 /* 334 * Set the VAX-DMA-specific registers, and copy the data if 335 * it is directed "outbound". 336 */ 337 if (dh->dh_flags & SIDH_OUT) { 338 vsbus_copyfromproc(dh->dh_proc, dh->dh_addr, 339 sc->ncr_addr + sc->ncr_off, dh->dh_len); 340 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 341 sc->ncr_dmadir, 0); 342 } else { 343 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 344 sc->ncr_dmadir, 1); 345 } 346 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 347 sc->ncr_dmacount, -dh->dh_len); 348 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 349 sc->ncr_dmaaddr, sc->ncr_off); 350 /* 351 * Now from the 5380-internal DMA registers. 352 */ 353 if (dh->dh_flags & SIDH_OUT) { 354 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 355 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 356 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 357 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 358 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 359 } else { 360 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 361 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 362 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 363 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 364 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 365 } 366 ncr_sc->sc_state |= NCR_DOINGDMA; 367 } 368 369 /* 370 * When? 371 */ 372 void 373 si_dma_poll(struct ncr5380_softc *ncr_sc) 374 { 375 printf("si_dma_poll\n"); 376 } 377 378 /* 379 * When? 380 */ 381 void 382 si_dma_eop(struct ncr5380_softc *ncr_sc) 383 { 384 printf("si_dma_eop\n"); 385 } 386 387 void 388 si_dma_stop(struct ncr5380_softc *ncr_sc) 389 { 390 struct si_softc *sc = (struct si_softc *)ncr_sc; 391 struct sci_req *sr = ncr_sc->sc_current; 392 struct si_dma_handle *dh = sr->sr_dma_hand; 393 int count, i; 394 395 if (ncr_sc->sc_state & NCR_DOINGDMA) 396 ncr_sc->sc_state &= ~NCR_DOINGDMA; 397 398 /* 399 * Sometimes the FIFO buffer isn't drained when the 400 * interrupt is posted. Just loop here and hope that 401 * it will drain soon. 402 */ 403 for (i = 0; i < 20000; i++) { 404 count = bus_space_read_4(ncr_sc->sc_regt, 405 ncr_sc->sc_regh, sc->ncr_dmacount); 406 if (count == 0) 407 break; 408 DELAY(100); 409 } 410 if (count == 0) { 411 if (((dh->dh_flags & SIDH_OUT) == 0)) { 412 vsbus_copytoproc(dh->dh_proc, 413 sc->ncr_addr + sc->ncr_off, 414 dh->dh_addr, dh->dh_len); 415 } 416 ncr_sc->sc_dataptr += dh->dh_len; 417 ncr_sc->sc_datalen -= dh->dh_len; 418 } 419 420 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 421 ~(SCI_MODE_DMA | SCI_MODE_DMA_IE)); 422 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 423 if (sc->onlyscsi == 0) 424 vsbus_dma_intr(); /* Try to start more transfers */ 425 } 426