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