Annotation of sys/arch/macppc/dev/esp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: esp.c,v 1.3 2007/04/22 22:31:14 deraadt Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
! 9: * Simulation Facility, NASA Ames Research Center.
! 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: * Copyright (c) 1994 Peter Galbavy
! 42: * 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: * 3. All advertising materials mentioning features or use of this software
! 53: * must display the following acknowledgement:
! 54: * This product includes software developed by Peter Galbavy
! 55: * 4. The name of the author may not be used to endorse or promote products
! 56: * derived from this software without specific prior written permission.
! 57: *
! 58: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 59: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 60: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 61: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 62: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 63: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 64: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 66: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 67: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 68: * POSSIBILITY OF SUCH DAMAGE.
! 69: */
! 70:
! 71: /*
! 72: * Based on aic6360 by Jarle Greipsland
! 73: *
! 74: * Acknowledgements: Many of the algorithms used in this driver are
! 75: * inspired by the work of Julian Elischer (julian@tfs.com) and
! 76: * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
! 77: */
! 78:
! 79: #include <sys/cdefs.h>
! 80:
! 81: #include <sys/types.h>
! 82: #include <sys/param.h>
! 83: #include <sys/systm.h>
! 84: #include <sys/kernel.h>
! 85: #include <sys/errno.h>
! 86: #include <sys/ioctl.h>
! 87: #include <sys/device.h>
! 88: #include <sys/buf.h>
! 89: #include <sys/proc.h>
! 90: #include <sys/user.h>
! 91: #include <sys/queue.h>
! 92: #include <sys/malloc.h>
! 93:
! 94: #include <uvm/uvm_extern.h>
! 95:
! 96: #include <scsi/scsi_all.h>
! 97: #include <scsi/scsiconf.h>
! 98: #include <scsi/scsi_message.h>
! 99:
! 100: #include <dev/ofw/openfirm.h>
! 101:
! 102: #include <machine/cpu.h>
! 103: #include <machine/autoconf.h>
! 104: #include <machine/pio.h>
! 105:
! 106: #include <dev/ic/ncr53c9xreg.h>
! 107: #include <dev/ic/ncr53c9xvar.h>
! 108:
! 109: #include <macppc/dev/dbdma.h>
! 110:
! 111: struct esp_softc {
! 112: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
! 113:
! 114: struct intrhand sc_ih; /* intr handler */
! 115:
! 116: volatile u_char *sc_reg; /* the registers */
! 117:
! 118: bus_dmamap_t sc_dmamap;
! 119: bus_dma_tag_t sc_dmat;
! 120: dbdma_t sc_dbdma;
! 121: dbdma_regmap_t *sc_dmareg; /* DMA registers */
! 122: dbdma_command_t *sc_dmacmd; /* command area for DMA */
! 123:
! 124: int sc_node; /* node ID */
! 125: int sc_intr;
! 126:
! 127: size_t sc_dmasize;
! 128: caddr_t *sc_dmaaddr;
! 129: size_t *sc_dmalen;
! 130: int sc_dmaactive;
! 131: int sc_dma_direction;
! 132: };
! 133:
! 134: #define D_WRITE 1
! 135: #define ESP_DMALIST_MAX 20
! 136:
! 137: void espattach(struct device *, struct device *, void *);
! 138: int espmatch(struct device *, void *, void *);
! 139:
! 140: /* Linkup to the rest of the kernel */
! 141: struct cfattach esp_ca = {
! 142: sizeof(struct esp_softc), espmatch, espattach
! 143: };
! 144:
! 145: struct scsi_adapter esp_switch = {
! 146: /* no max at this level; handled by DMA code */
! 147: ncr53c9x_scsi_cmd, minphys, NULL, NULL,
! 148: };
! 149:
! 150: struct scsi_device esp_dev = {
! 151: NULL, NULL, NULL, NULL,
! 152: };
! 153:
! 154: /*
! 155: * Functions and the switch for the MI code.
! 156: */
! 157: u_char esp_read_reg(struct ncr53c9x_softc *, int);
! 158: void esp_write_reg(struct ncr53c9x_softc *, int, u_char);
! 159: int esp_dma_isintr(struct ncr53c9x_softc *);
! 160: void esp_dma_reset(struct ncr53c9x_softc *);
! 161: int esp_dma_intr(struct ncr53c9x_softc *);
! 162: int esp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
! 163: size_t *, int, size_t *);
! 164: void esp_dma_go(struct ncr53c9x_softc *);
! 165: void esp_dma_stop(struct ncr53c9x_softc *);
! 166: int esp_dma_isactive(struct ncr53c9x_softc *);
! 167:
! 168: struct ncr53c9x_glue esp_glue = {
! 169: esp_read_reg,
! 170: esp_write_reg,
! 171: esp_dma_isintr,
! 172: esp_dma_reset,
! 173: esp_dma_intr,
! 174: esp_dma_setup,
! 175: esp_dma_go,
! 176: esp_dma_stop,
! 177: esp_dma_isactive,
! 178: NULL, /* gl_clear_latched_intr */
! 179: };
! 180:
! 181: static int espdmaintr(struct esp_softc *);
! 182: static void esp_shutdownhook(void *);
! 183:
! 184: int
! 185: espmatch(struct device *parent, void *cf, void *aux)
! 186: {
! 187: struct confargs *ca = aux;
! 188:
! 189: if (strcmp(ca->ca_name, "53c94") != 0)
! 190: return 0;
! 191:
! 192: if (ca->ca_nreg != 16)
! 193: return 0;
! 194: if (ca->ca_nintr != 8)
! 195: return 0;
! 196:
! 197: return 1;
! 198: }
! 199:
! 200: /*
! 201: * Attach this instance, and then all the sub-devices
! 202: */
! 203: void
! 204: espattach(struct device *parent, struct device *self, void *aux)
! 205: {
! 206: struct confargs *ca = aux;
! 207: struct esp_softc *esc = (void *)self;
! 208: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
! 209: u_int *reg;
! 210: int sz, error;
! 211:
! 212: /*
! 213: * Set up glue for MI code early; we use some of it here.
! 214: */
! 215: sc->sc_glue = &esp_glue;
! 216:
! 217: esc->sc_node = ca->ca_node;
! 218: esc->sc_intr = ca->ca_intr[0];
! 219: printf(" irq %d", esc->sc_intr);
! 220:
! 221: /*
! 222: * Map my registers in.
! 223: */
! 224: reg = ca->ca_reg;
! 225: esc->sc_reg = mapiodev(ca->ca_baseaddr + reg[0], reg[1]);
! 226: esc->sc_dmareg = mapiodev(ca->ca_baseaddr + reg[2], reg[3]);
! 227:
! 228: esc->sc_dmat = ca->ca_dmat;
! 229: if ((error = bus_dmamap_create(esc->sc_dmat,
! 230: ESP_DMALIST_MAX * DBDMA_COUNT_MAX, ESP_DMALIST_MAX,
! 231: DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &esc->sc_dmamap)) != 0) {
! 232: printf(": cannot create dma map, error = %d\n", error);
! 233: return;
! 234: }
! 235:
! 236: /* Allocate 16-byte aligned DMA command space */
! 237: esc->sc_dbdma = dbdma_alloc(esc->sc_dmat, ESP_DMALIST_MAX);
! 238: esc->sc_dmacmd = esc->sc_dbdma->d_addr;
! 239:
! 240: /* Other settings */
! 241: sc->sc_id = 7;
! 242: sz = OF_getprop(ca->ca_node, "clock-frequency",
! 243: &sc->sc_freq, sizeof(int));
! 244: if (sz != sizeof(int))
! 245: sc->sc_freq = 25000000;
! 246:
! 247: /* gimme MHz */
! 248: sc->sc_freq /= 1000000;
! 249:
! 250: /*
! 251: * Set up static configuration info.
! 252: */
! 253: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
! 254: sc->sc_cfg2 = NCRCFG2_SCSI2; /* | NCRCFG2_FE */
! 255: sc->sc_cfg3 = NCRCFG3_CDB;
! 256: sc->sc_rev = NCR_VARIANT_NCR53C94;
! 257:
! 258: /*
! 259: * This is the value used to start sync negotiations
! 260: * Note that the NCR register "SYNCTP" is programmed
! 261: * in "clocks per byte", and has a minimum value of 4.
! 262: * The SCSI period used in negotiation is one-fourth
! 263: * of the time (in nanoseconds) needed to transfer one byte.
! 264: * Since the chip's clock is given in MHz, we have the following
! 265: * formula: 4 * period = (1000 / freq) * 4
! 266: */
! 267: sc->sc_minsync = 1000 / sc->sc_freq;
! 268:
! 269: sc->sc_maxxfer = 64 * 1024;
! 270:
! 271: /* and the interuppts */
! 272: mac_intr_establish(parent, esc->sc_intr, IST_LEVEL, IPL_BIO,
! 273: ncr53c9x_intr, sc, sc->sc_dev.dv_xname);
! 274:
! 275: /* Reset SCSI bus when halt. */
! 276: shutdownhook_establish(esp_shutdownhook, sc);
! 277:
! 278: /* Turn on target selection using the `DMA' method */
! 279: sc->sc_features |= NCR_F_DMASELECT;
! 280:
! 281: ncr53c9x_attach(sc, &esp_switch, &esp_dev);
! 282:
! 283: }
! 284:
! 285: /*
! 286: * Glue functions.
! 287: */
! 288:
! 289: u_char
! 290: esp_read_reg(struct ncr53c9x_softc *sc, int reg)
! 291: {
! 292: struct esp_softc *esc = (struct esp_softc *)sc;
! 293:
! 294: return in8(&esc->sc_reg[reg * 16]);
! 295: }
! 296:
! 297: void
! 298: esp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char val)
! 299: {
! 300: struct esp_softc *esc = (struct esp_softc *)sc;
! 301: u_char v = val;
! 302:
! 303: out8(&esc->sc_reg[reg * 16], v);
! 304: }
! 305:
! 306: int
! 307: esp_dma_isintr(struct ncr53c9x_softc *sc)
! 308: {
! 309: return esp_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
! 310: }
! 311:
! 312: void
! 313: esp_dma_reset(struct ncr53c9x_softc *sc)
! 314: {
! 315: struct esp_softc *esc = (struct esp_softc *)sc;
! 316:
! 317: dbdma_stop(esc->sc_dmareg);
! 318: esc->sc_dmaactive = 0;
! 319: }
! 320:
! 321: int
! 322: esp_dma_intr(struct ncr53c9x_softc *sc)
! 323: {
! 324: struct esp_softc *esc = (struct esp_softc *)sc;
! 325:
! 326: return (espdmaintr(esc));
! 327: }
! 328:
! 329: int
! 330: esp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
! 331: int datain, size_t *dmasize)
! 332: {
! 333: struct esp_softc *esc = (struct esp_softc *)sc;
! 334: dbdma_command_t *cmdp;
! 335: u_int cmd;
! 336: int i, error;
! 337:
! 338: cmdp = esc->sc_dmacmd;
! 339: cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
! 340:
! 341: esc->sc_dmaaddr = addr;
! 342: esc->sc_dmalen = len;
! 343: esc->sc_dmasize = *dmasize;
! 344:
! 345: if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_dmamap, *addr,
! 346: *dmasize, NULL, BUS_DMA_NOWAIT)) != 0)
! 347: return (error);
! 348:
! 349: for (i = 0; i < esc->sc_dmamap->dm_nsegs; i++, cmdp++) {
! 350: if (i + 1 == esc->sc_dmamap->dm_nsegs)
! 351: cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
! 352: DBDMA_BUILD(cmdp, cmd, 0, esc->sc_dmamap->dm_segs[i].ds_len,
! 353: esc->sc_dmamap->dm_segs[i].ds_addr, DBDMA_INT_NEVER,
! 354: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 355: }
! 356: DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
! 357: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 358:
! 359: esc->sc_dma_direction = datain ? D_WRITE : 0;
! 360:
! 361: return 0;
! 362: }
! 363:
! 364: void
! 365: esp_dma_go(struct ncr53c9x_softc *sc)
! 366: {
! 367: struct esp_softc *esc = (struct esp_softc *)sc;
! 368:
! 369: dbdma_start(esc->sc_dmareg, esc->sc_dbdma);
! 370: esc->sc_dmaactive = 1;
! 371: }
! 372:
! 373: void
! 374: esp_dma_stop(struct ncr53c9x_softc *sc)
! 375: {
! 376: struct esp_softc *esc = (struct esp_softc *)sc;
! 377:
! 378: dbdma_stop(esc->sc_dmareg);
! 379: bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap);
! 380: esc->sc_dmaactive = 0;
! 381: }
! 382:
! 383: int
! 384: esp_dma_isactive(struct ncr53c9x_softc *sc)
! 385: {
! 386: struct esp_softc *esc = (struct esp_softc *)sc;
! 387:
! 388: return (esc->sc_dmaactive);
! 389: }
! 390:
! 391:
! 392: /*
! 393: * Pseudo (chained) interrupt from the esp driver to kick the
! 394: * current running DMA transfer. I am replying on espintr() to
! 395: * pickup and clean errors for now
! 396: *
! 397: * return 1 if it was a DMA continue.
! 398: */
! 399: int
! 400: espdmaintr(struct esp_softc *sc)
! 401: {
! 402: struct ncr53c9x_softc *nsc = (struct ncr53c9x_softc *)sc;
! 403: int trans, resid;
! 404: u_long csr = sc->sc_dma_direction;
! 405:
! 406: /* This is an "assertion" :) */
! 407: if (sc->sc_dmaactive == 0)
! 408: panic("dmaintr: DMA wasn't active");
! 409:
! 410: /* DMA has stopped */
! 411: dbdma_stop(sc->sc_dmareg);
! 412: bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
! 413: sc->sc_dmaactive = 0;
! 414:
! 415: if (sc->sc_dmasize == 0) {
! 416: /* A "Transfer Pad" operation completed */
! 417: NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
! 418: NCR_READ_REG(nsc, NCR_TCL) |
! 419: (NCR_READ_REG(nsc, NCR_TCM) << 8),
! 420: NCR_READ_REG(nsc, NCR_TCL),
! 421: NCR_READ_REG(nsc, NCR_TCM)));
! 422: return 0;
! 423: }
! 424:
! 425: resid = 0;
! 426: /*
! 427: * If a transfer onto the SCSI bus gets interrupted by the device
! 428: * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
! 429: * as residual since the ESP counter registers get decremented as
! 430: * bytes are clocked into the FIFO.
! 431: */
! 432: if (!(csr & D_WRITE) &&
! 433: (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
! 434: NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid));
! 435: }
! 436:
! 437: if ((nsc->sc_espstat & NCRSTAT_TC) == 0) {
! 438: /*
! 439: * `Terminal count' is off, so read the residue
! 440: * out of the ESP counter registers.
! 441: */
! 442: resid += (NCR_READ_REG(nsc, NCR_TCL) |
! 443: (NCR_READ_REG(nsc, NCR_TCM) << 8) |
! 444: ((nsc->sc_cfg2 & NCRCFG2_FE)
! 445: ? (NCR_READ_REG(nsc, NCR_TCH) << 16) : 0));
! 446:
! 447: if (resid == 0 && sc->sc_dmasize == 65536 &&
! 448: (nsc->sc_cfg2 & NCRCFG2_FE) == 0)
! 449: /* A transfer of 64K is encoded as `TCL=TCM=0' */
! 450: resid = 65536;
! 451: }
! 452:
! 453: trans = sc->sc_dmasize - resid;
! 454: if (trans < 0) { /* transferred < 0 ? */
! 455: trans = sc->sc_dmasize;
! 456: }
! 457:
! 458: NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
! 459: NCR_READ_REG(nsc, NCR_TCL), NCR_READ_REG(nsc, NCR_TCM),
! 460: (nsc->sc_cfg2 & NCRCFG2_FE) ? NCR_READ_REG(nsc, NCR_TCH) : 0,
! 461: trans, resid));
! 462:
! 463:
! 464: *sc->sc_dmalen -= trans;
! 465: *sc->sc_dmaaddr += trans;
! 466:
! 467: return 0;
! 468: }
! 469:
! 470: void
! 471: esp_shutdownhook(void *arg)
! 472: {
! 473: struct ncr53c9x_softc *sc = arg;
! 474:
! 475: NCRCMD(sc, NCRCMD_RSTSCSI);
! 476: }
CVSweb