Annotation of sys/dev/tc/asc_tcds.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: asc_tcds.c,v 1.4 2005/05/22 19:40:51 art Exp $ */
! 2: /* $NetBSD: asc_tcds.c,v 1.5 2001/11/15 09:48:19 lukem Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: /*
! 42: * Copyright (c) 1994 Peter Galbavy. All rights reserved.
! 43: *
! 44: * Redistribution and use in source and binary forms, with or without
! 45: * modification, are permitted provided that the following conditions
! 46: * are met:
! 47: * 1. Redistributions of source code must retain the above copyright
! 48: * notice, this list of conditions and the following disclaimer.
! 49: * 2. Redistributions in binary form must reproduce the above copyright
! 50: * notice, this list of conditions and the following disclaimer in the
! 51: * documentation and/or other materials provided with the distribution.
! 52: *
! 53: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 54: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 55: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 56: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 57: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 58: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 59: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 60: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 61: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 62: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 63: */
! 64:
! 65: #include <sys/param.h>
! 66: #include <sys/systm.h>
! 67: #include <sys/device.h>
! 68: #include <sys/buf.h>
! 69:
! 70: #include <scsi/scsi_all.h>
! 71: #include <scsi/scsiconf.h>
! 72:
! 73: #include <dev/ic/ncr53c9xreg.h>
! 74: #include <dev/ic/ncr53c9xvar.h>
! 75: #include <dev/tc/ascvar.h>
! 76:
! 77: #include <machine/bus.h>
! 78:
! 79: #include <dev/tc/tcvar.h>
! 80: #include <dev/tc/tcdsreg.h>
! 81: #include <dev/tc/tcdsvar.h>
! 82:
! 83: struct asc_tcds_softc {
! 84: struct asc_softc asc;
! 85:
! 86: struct tcds_slotconfig *sc_tcds;
! 87: };
! 88:
! 89: int asc_tcds_match (struct device *, void *, void *);
! 90: void asc_tcds_attach(struct device *, struct device *, void *);
! 91:
! 92: /* Linkup to the rest of the kernel */
! 93: struct cfattach asc_tcds_ca = {
! 94: sizeof(struct asc_tcds_softc), asc_tcds_match, asc_tcds_attach
! 95: };
! 96:
! 97: /*
! 98: * Functions and the switch for the MI code.
! 99: */
! 100: int tcds_dma_isintr(struct ncr53c9x_softc *);
! 101: void tcds_dma_reset(struct ncr53c9x_softc *);
! 102: int tcds_dma_intr(struct ncr53c9x_softc *);
! 103: int tcds_dma_setup(struct ncr53c9x_softc *, caddr_t *,
! 104: size_t *, int, size_t *);
! 105: void tcds_dma_go(struct ncr53c9x_softc *);
! 106: void tcds_dma_stop(struct ncr53c9x_softc *);
! 107: int tcds_dma_isactive(struct ncr53c9x_softc *);
! 108: void tcds_clear_latched_intr(struct ncr53c9x_softc *);
! 109:
! 110: struct ncr53c9x_glue asc_tcds_glue = {
! 111: asc_read_reg,
! 112: asc_write_reg,
! 113: tcds_dma_isintr,
! 114: tcds_dma_reset,
! 115: tcds_dma_intr,
! 116: tcds_dma_setup,
! 117: tcds_dma_go,
! 118: tcds_dma_stop,
! 119: tcds_dma_isactive,
! 120: tcds_clear_latched_intr,
! 121: };
! 122:
! 123: extern struct scsi_adapter asc_switch;
! 124: extern struct scsi_device asc_dev;
! 125:
! 126: int
! 127: asc_tcds_match(parent, cf, aux)
! 128: struct device *parent;
! 129: void *cf, *aux;
! 130: {
! 131:
! 132: /* We always exist. */
! 133: return 1;
! 134: }
! 135:
! 136: #define DMAMAX(a) (NBPG - ((a) & (NBPG - 1)))
! 137:
! 138: /*
! 139: * Attach this instance, and then all the sub-devices
! 140: */
! 141: void
! 142: asc_tcds_attach(parent, self, aux)
! 143: struct device *parent, *self;
! 144: void *aux;
! 145: {
! 146: struct tcdsdev_attach_args *tcdsdev = aux;
! 147: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)self;
! 148: struct ncr53c9x_softc *sc = &asc->asc.sc_ncr53c9x;
! 149: int error;
! 150:
! 151: /*
! 152: * Set up glue for MI code early; we use some of it here.
! 153: */
! 154: sc->sc_glue = &asc_tcds_glue;
! 155:
! 156: asc->asc.sc_bst = tcdsdev->tcdsda_bst;
! 157: asc->asc.sc_bsh = tcdsdev->tcdsda_bsh;
! 158: asc->sc_tcds = tcdsdev->tcdsda_sc;
! 159:
! 160: /*
! 161: * The TCDS ASIC cannot DMA across 8k boundaries, and this
! 162: * driver is written such that each DMA segment gets a new
! 163: * call to tcds_dma_setup(). Thus, the DMA map only needs
! 164: * to support 8k transfers.
! 165: */
! 166: asc->asc.sc_dmat = tcdsdev->tcdsda_dmat;
! 167: if ((error = bus_dmamap_create(asc->asc.sc_dmat, NBPG, 1, NBPG,
! 168: NBPG, BUS_DMA_NOWAIT, &asc->asc.sc_dmamap)) < 0) {
! 169: printf("failed to create dma map, error = %d\n", error);
! 170: }
! 171:
! 172: sc->sc_id = tcdsdev->tcdsda_id;
! 173: sc->sc_freq = tcdsdev->tcdsda_freq;
! 174:
! 175: /* gimme MHz */
! 176: sc->sc_freq /= 1000000;
! 177:
! 178: tcds_intr_establish(parent, tcdsdev->tcdsda_chip, ncr53c9x_intr, sc);
! 179:
! 180: /*
! 181: * XXX More of this should be in ncr53c9x_attach(), but
! 182: * XXX should we really poke around the chip that much in
! 183: * XXX the MI code? Think about this more...
! 184: */
! 185:
! 186: /*
! 187: * Set up static configuration info.
! 188: */
! 189: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
! 190: sc->sc_cfg2 = NCRCFG2_SCSI2;
! 191: sc->sc_cfg3 = NCRCFG3_CDB;
! 192: if (sc->sc_freq > 25)
! 193: sc->sc_cfg3 |= NCRF9XCFG3_FCLK;
! 194: sc->sc_rev = tcdsdev->tcdsda_variant;
! 195: if (tcdsdev->tcdsda_fast) {
! 196: sc->sc_features |= NCR_F_FASTSCSI;
! 197: sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI;
! 198: }
! 199:
! 200: /*
! 201: * XXX minsync and maxxfer _should_ be set up in MI code,
! 202: * XXX but it appears to have some dependency on what sort
! 203: * XXX of DMA we're hooked up to, etc.
! 204: */
! 205:
! 206: /*
! 207: * This is the value used to start sync negotiations
! 208: * Note that the NCR register "SYNCTP" is programmed
! 209: * in "clocks per byte", and has a minimum value of 4.
! 210: * The SCSI period used in negotiation is one-fourth
! 211: * of the time (in nanoseconds) needed to transfer one byte.
! 212: * Since the chip's clock is given in MHz, we have the following
! 213: * formula: 4 * period = (1000 / freq) * 4
! 214: */
! 215: sc->sc_minsync = (1000 / sc->sc_freq) * tcdsdev->tcdsda_period / 4;
! 216:
! 217: sc->sc_maxxfer = 64 * 1024;
! 218:
! 219: /* Do the common parts of attachment. */
! 220: ncr53c9x_attach(sc, &asc_switch, &asc_dev);
! 221: }
! 222:
! 223: void
! 224: tcds_dma_reset(sc)
! 225: struct ncr53c9x_softc *sc;
! 226: {
! 227: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 228:
! 229: /* TCDS SCSI disable/reset/enable. */
! 230: tcds_scsi_reset(asc->sc_tcds); /* XXX */
! 231:
! 232: if (asc->asc.sc_flags & ASC_MAPLOADED)
! 233: bus_dmamap_unload(asc->asc.sc_dmat, asc->asc.sc_dmamap);
! 234: asc->asc.sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
! 235: }
! 236:
! 237: /*
! 238: * start a dma transfer or keep it going
! 239: */
! 240: int
! 241: tcds_dma_setup(sc, addr, len, ispullup, dmasize)
! 242: struct ncr53c9x_softc *sc;
! 243: caddr_t *addr;
! 244: size_t *len, *dmasize;
! 245: int ispullup; /* DMA into main memory */
! 246: {
! 247: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 248: struct tcds_slotconfig *tcds = asc->sc_tcds;
! 249: size_t size;
! 250: u_int32_t dic;
! 251:
! 252: NCR_DMA(("tcds_dma %d: start %d@%p,%s\n", tcds->sc_slot,
! 253: (int)*asc->asc.sc_dmalen, *asc->asc.sc_dmaaddr,
! 254: (ispullup) ? "IN" : "OUT"));
! 255:
! 256: /*
! 257: * the rules say we cannot transfer more than the limit
! 258: * of this DMA chip (64k) and we cannot cross a 8k boundary.
! 259: */
! 260: size = min(*dmasize, DMAMAX((size_t)*addr));
! 261: asc->asc.sc_dmaaddr = addr;
! 262: asc->asc.sc_dmalen = len;
! 263: asc->asc.sc_flags = (ispullup) ? ASC_ISPULLUP : 0;
! 264: *dmasize = asc->asc.sc_dmasize = size;
! 265:
! 266: NCR_DMA(("dma_start: dmasize = %d\n", (int)size));
! 267:
! 268: if (size == 0)
! 269: return 0;
! 270:
! 271: if (bus_dmamap_load(asc->asc.sc_dmat, asc->asc.sc_dmamap, *addr, size,
! 272: NULL, BUS_DMA_NOWAIT | (ispullup ? BUS_DMA_READ : BUS_DMA_WRITE))) {
! 273: /*
! 274: * XXX Should return an error, here, but the upper-layer
! 275: * XXX doesn't check the return value!
! 276: */
! 277: panic("tcds_dma_setup: dmamap load failed");
! 278: }
! 279:
! 280: /* synchronize dmamap contents with memory image */
! 281: bus_dmamap_sync(asc->asc.sc_dmat, asc->asc.sc_dmamap, 0, size,
! 282: (ispullup) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
! 283:
! 284: /* load address, set/clear unaligned transfer and read/write bits. */
! 285: bus_space_write_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_sda,
! 286: asc->asc.sc_dmamap->dm_segs[0].ds_addr >> 2);
! 287: dic = bus_space_read_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_dic);
! 288: dic &= ~TCDS_DIC_ADDRMASK;
! 289: dic |= asc->asc.sc_dmamap->dm_segs[0].ds_addr & TCDS_DIC_ADDRMASK;
! 290: if (ispullup)
! 291: dic |= TCDS_DIC_WRITE;
! 292: else
! 293: dic &= ~TCDS_DIC_WRITE;
! 294: bus_space_write_4(tcds->sc_bst, tcds->sc_bsh, tcds->sc_dic, dic);
! 295:
! 296: asc->asc.sc_flags |= ASC_MAPLOADED;
! 297: return 0;
! 298: }
! 299:
! 300: void
! 301: tcds_dma_go(sc)
! 302: struct ncr53c9x_softc *sc;
! 303: {
! 304: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 305:
! 306: /* mark unit as DMA-active */
! 307: asc->asc.sc_flags |= ASC_DMAACTIVE;
! 308:
! 309: /* start DMA */
! 310: tcds_dma_enable(asc->sc_tcds, 1);
! 311: }
! 312:
! 313: void
! 314: tcds_dma_stop(sc)
! 315: struct ncr53c9x_softc *sc;
! 316: {
! 317: #if 0
! 318: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 319: #endif
! 320:
! 321: /*
! 322: * XXX STOP DMA HERE!
! 323: */
! 324: }
! 325:
! 326: /*
! 327: * Pseudo (chained) interrupt from the asc driver to kick the
! 328: * current running DMA transfer. Called from ncr53c9x_intr()
! 329: * for now.
! 330: *
! 331: * return 1 if it was a DMA continue.
! 332: */
! 333: int
! 334: tcds_dma_intr(sc)
! 335: struct ncr53c9x_softc *sc;
! 336: {
! 337: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 338: struct tcds_slotconfig *tcds = asc->sc_tcds;
! 339: int trans, resid;
! 340: u_int32_t tcl, tcm;
! 341: u_int32_t dud, dudmask, *addr;
! 342: bus_addr_t pa;
! 343:
! 344: NCR_DMA(("tcds_dma %d: intr", tcds->sc_slot));
! 345:
! 346: if (tcds_scsi_iserr(tcds))
! 347: return 0;
! 348:
! 349: /* This is an "assertion" :) */
! 350: if ((asc->asc.sc_flags & ASC_DMAACTIVE) == 0)
! 351: panic("tcds_dma_intr: DMA wasn't active");
! 352:
! 353: /* DMA has stopped */
! 354: tcds_dma_enable(tcds, 0);
! 355: asc->asc.sc_flags &= ~ASC_DMAACTIVE;
! 356:
! 357: if (asc->asc.sc_dmasize == 0) {
! 358: /* A "Transfer Pad" operation completed */
! 359: tcl = NCR_READ_REG(sc, NCR_TCL);
! 360: tcm = NCR_READ_REG(sc, NCR_TCM);
! 361: NCR_DMA(("dma_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
! 362: tcl | (tcm << 8), tcl, tcm));
! 363: return 0;
! 364: }
! 365:
! 366: resid = 0;
! 367: if ((asc->asc.sc_flags & ASC_ISPULLUP) == 0 &&
! 368: (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
! 369: NCR_DMA(("dma_intr: empty esp FIFO of %d ", resid));
! 370: DELAY(1);
! 371: }
! 372:
! 373: resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
! 374: resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
! 375:
! 376: trans = asc->asc.sc_dmasize - resid;
! 377: if (trans < 0) { /* transferred < 0 ? */
! 378: printf("tcds_dma %d: xfer (%d) > req (%d)\n",
! 379: tcds->sc_slot, trans, (int)asc->asc.sc_dmasize);
! 380: trans = asc->asc.sc_dmasize;
! 381: }
! 382:
! 383: NCR_DMA(("dma_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
! 384: tcl, tcm, trans, resid));
! 385:
! 386: *asc->asc.sc_dmalen -= trans;
! 387: *asc->asc.sc_dmaaddr += trans;
! 388:
! 389: bus_dmamap_sync(asc->asc.sc_dmat, asc->asc.sc_dmamap,
! 390: 0, asc->asc.sc_dmamap->dm_mapsize,
! 391: (asc->asc.sc_flags & ASC_ISPULLUP)
! 392: ? BUS_DMASYNC_POSTREAD
! 393: : BUS_DMASYNC_POSTWRITE);
! 394:
! 395: /*
! 396: * Clean up unaligned DMAs into main memory.
! 397: */
! 398: if (asc->asc.sc_flags & ASC_ISPULLUP) {
! 399: /* Handle unaligned starting address, length. */
! 400: dud = bus_space_read_4(tcds->sc_bst,
! 401: tcds->sc_bsh, tcds->sc_dud0);
! 402: if ((dud & TCDS_DUD0_VALIDBITS) != 0) {
! 403: addr = (u_int32_t *)
! 404: ((paddr_t)*asc->asc.sc_dmaaddr & ~0x3);
! 405: dudmask = 0;
! 406: if (dud & TCDS_DUD0_VALID00)
! 407: panic("tcds_dma: dud0 byte 0 valid");
! 408: if (dud & TCDS_DUD0_VALID01)
! 409: dudmask |= TCDS_DUD_BYTE01;
! 410: if (dud & TCDS_DUD0_VALID10)
! 411: dudmask |= TCDS_DUD_BYTE10;
! 412: #ifdef DIAGNOSTIC
! 413: if (dud & TCDS_DUD0_VALID11)
! 414: dudmask |= TCDS_DUD_BYTE11;
! 415: #endif
! 416: NCR_DMA(("dud0 at %p dudmask 0x%x\n",
! 417: addr, dudmask));
! 418: *addr = (*addr & ~dudmask) | (dud & dudmask);
! 419: }
! 420: dud = bus_space_read_4(tcds->sc_bst,
! 421: tcds->sc_bsh, tcds->sc_dud1);
! 422: if ((dud & TCDS_DUD1_VALIDBITS) != 0) {
! 423: pa = bus_space_read_4(tcds->sc_bst, tcds->sc_bsh,
! 424: tcds->sc_sda) << 2;
! 425: dudmask = 0;
! 426: if (dud & TCDS_DUD1_VALID00)
! 427: dudmask |= TCDS_DUD_BYTE00;
! 428: if (dud & TCDS_DUD1_VALID01)
! 429: dudmask |= TCDS_DUD_BYTE01;
! 430: if (dud & TCDS_DUD1_VALID10)
! 431: dudmask |= TCDS_DUD_BYTE10;
! 432: #ifdef DIAGNOSTIC
! 433: if (dud & TCDS_DUD1_VALID11)
! 434: panic("tcds_dma: dud1 byte 3 valid");
! 435: #endif
! 436: NCR_DMA(("dud1 at 0x%lx dudmask 0x%x\n",
! 437: pa, dudmask));
! 438: /* XXX Fix TC_PHYS_TO_UNCACHED() */
! 439: #if defined(__alpha__)
! 440: addr = (u_int32_t *)ALPHA_PHYS_TO_K0SEG(pa);
! 441: #elif defined(__mips__)
! 442: addr = (u_int32_t *)MIPS_PHYS_TO_KSEG1(pa);
! 443: #else
! 444: #error TURBOchannel only exists on DECs, folks...
! 445: #endif
! 446: *addr = (*addr & ~dudmask) | (dud & dudmask);
! 447: }
! 448: /* XXX deal with saved residual byte? */
! 449: }
! 450:
! 451: bus_dmamap_unload(asc->asc.sc_dmat, asc->asc.sc_dmamap);
! 452: asc->asc.sc_flags &= ~ASC_MAPLOADED;
! 453:
! 454: return 0;
! 455: }
! 456:
! 457: /*
! 458: * Glue functions.
! 459: */
! 460: int
! 461: tcds_dma_isintr(sc)
! 462: struct ncr53c9x_softc *sc;
! 463: {
! 464: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 465: int x;
! 466:
! 467: x = tcds_scsi_isintr(asc->sc_tcds, 1);
! 468:
! 469: /* XXX */
! 470: return x;
! 471: }
! 472:
! 473: int
! 474: tcds_dma_isactive(sc)
! 475: struct ncr53c9x_softc *sc;
! 476: {
! 477: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 478:
! 479: return !!(asc->asc.sc_flags & ASC_DMAACTIVE);
! 480: }
! 481:
! 482: void
! 483: tcds_clear_latched_intr(sc)
! 484: struct ncr53c9x_softc *sc;
! 485: {
! 486: struct asc_tcds_softc *asc = (struct asc_tcds_softc *)sc;
! 487:
! 488: /* Clear the TCDS interrupt bit. */
! 489: (void)tcds_scsi_isintr(asc->sc_tcds, 1);
! 490: }
CVSweb