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