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