1130293Sscottl/*- 2130293Sscottl * Copyright (c) 2004 Scott Long 3130293Sscottl * All rights reserved. 4130293Sscottl * 5130293Sscottl * Redistribution and use in source and binary forms, with or without 6130293Sscottl * modification, are permitted provided that the following conditions 7130293Sscottl * are met: 8130293Sscottl * 1. Redistributions of source code must retain the above copyright 9130293Sscottl * notice, this list of conditions and the following disclaimer. 10130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11130293Sscottl * notice, this list of conditions and the following disclaimer in the 12130293Sscottl * documentation and/or other materials provided with the distribution. 13130293Sscottl * 14130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130293Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130293Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130293Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130293Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130293Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130293Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130293Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130293Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130293Sscottl * SUCH DAMAGE. 25130293Sscottl * 26130293Sscottl */ 27130293Sscottl 28219567Smarius/* $NetBSD: lsi64854.c,v 1.33 2008/04/28 20:23:50 martin Exp $ */ 29130293Sscottl 30130293Sscottl/*- 31130293Sscottl * Copyright (c) 1998 The NetBSD Foundation, Inc. 32130293Sscottl * All rights reserved. 33130293Sscottl * 34130293Sscottl * This code is derived from software contributed to The NetBSD Foundation 35130293Sscottl * by Paul Kranenburg. 36130293Sscottl * 37130293Sscottl * Redistribution and use in source and binary forms, with or without 38130293Sscottl * modification, are permitted provided that the following conditions 39130293Sscottl * are met: 40130293Sscottl * 1. Redistributions of source code must retain the above copyright 41130293Sscottl * notice, this list of conditions and the following disclaimer. 42130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 43130293Sscottl * notice, this list of conditions and the following disclaimer in the 44130293Sscottl * documentation and/or other materials provided with the distribution. 45130293Sscottl * 46130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 47130293Sscottl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 48130293Sscottl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49130293Sscottl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 50130293Sscottl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51130293Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52130293Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53130293Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54130293Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55130293Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56130293Sscottl * POSSIBILITY OF SUCH DAMAGE. 57130293Sscottl */ 58130293Sscottl 59130293Sscottl#include <sys/cdefs.h> 60130293Sscottl__FBSDID("$FreeBSD$"); 61130293Sscottl 62130293Sscottl#include <sys/param.h> 63130293Sscottl#include <sys/systm.h> 64130293Sscottl#include <sys/bus.h> 65130293Sscottl#include <sys/kernel.h> 66130293Sscottl#include <sys/lock.h> 67130293Sscottl#include <sys/mutex.h> 68182876Smarius#include <sys/rman.h> 69130293Sscottl 70130293Sscottl#include <machine/bus.h> 71130293Sscottl 72130293Sscottl#include <cam/cam.h> 73130293Sscottl#include <cam/cam_ccb.h> 74130293Sscottl#include <cam/scsi/scsi_all.h> 75130293Sscottl 76137532Strhodes#include <sparc64/sbus/lsi64854reg.h> 77137532Strhodes#include <sparc64/sbus/lsi64854var.h> 78130293Sscottl 79130293Sscottl#include <dev/esp/ncr53c9xreg.h> 80130293Sscottl#include <dev/esp/ncr53c9xvar.h> 81130293Sscottl 82130293Sscottl#ifdef DEBUG 83130293Sscottl#define LDB_SCSI 1 84130293Sscottl#define LDB_ENET 2 85130293Sscottl#define LDB_PP 4 86130293Sscottl#define LDB_ANY 0xff 87130293Sscottlint lsi64854debug = 0; 88226917Smarius#define DPRINTF(a,x) \ 89226917Smarius do { \ 90226917Smarius if ((lsi64854debug & (a)) != 0) \ 91226917Smarius printf x; \ 92226917Smarius } while (/* CONSTCOND */0) 93130293Sscottl#else 94130293Sscottl#define DPRINTF(a,x) 95130293Sscottl#endif 96130293Sscottl 97227302Smarius/* 98227302Smarius * The rules say we cannot transfer more than the limit of this DMA chip (64k 99227302Smarius * for old and 16Mb for new), and we cannot cross a 16Mb boundary. 100227302Smarius */ 101227302Smarius#define MAX_DMA_SZ (64 * 1024) 102227302Smarius#define BOUNDARY (16 * 1024 * 1024) 103130293Sscottl 104155089Smariusstatic void lsi64854_reset(struct lsi64854_softc *); 105155089Smariusstatic void lsi64854_map_scsi(void *, bus_dma_segment_t *, int, int); 106226917Smariusstatic int lsi64854_setup(struct lsi64854_softc *, void **, size_t *, 107155089Smarius int, size_t *); 108155089Smariusstatic int lsi64854_scsi_intr(void *); 109155089Smariusstatic int lsi64854_enet_intr(void *); 110226917Smariusstatic int lsi64854_setup_pp(struct lsi64854_softc *, void **, 111226917Smarius size_t *, int, size_t *); 112155089Smariusstatic int lsi64854_pp_intr(void *); 113155089Smarius 114130293Sscottl/* 115130293Sscottl * Finish attaching this DMA device. 116130293Sscottl * Front-end must fill in these fields: 117182876Smarius * sc_res 118130293Sscottl * sc_burst 119130293Sscottl * sc_channel (one of SCSI, ENET, PP) 120130293Sscottl * sc_client (one of SCSI, ENET, PP `soft_c' pointers) 121130293Sscottl */ 122146392Smariusint 123130293Sscottllsi64854_attach(struct lsi64854_softc *sc) 124130293Sscottl{ 125182876Smarius bus_dma_lock_t *lockfunc; 126182876Smarius struct ncr53c9x_softc *nsc; 127182876Smarius void *lockfuncarg; 128145190Smarius uint32_t csr; 129146392Smarius int error; 130130293Sscottl 131182876Smarius lockfunc = NULL; 132182876Smarius lockfuncarg = NULL; 133227302Smarius sc->sc_maxdmasize = MAX_DMA_SZ; 134182876Smarius 135130293Sscottl switch (sc->sc_channel) { 136130293Sscottl case L64854_CHANNEL_SCSI: 137182876Smarius nsc = sc->sc_client; 138182876Smarius if (NCR_LOCK_INITIALIZED(nsc) == 0) { 139182876Smarius device_printf(sc->sc_dev, "mutex not initialized\n"); 140182876Smarius return (ENXIO); 141182876Smarius } 142182876Smarius lockfunc = busdma_lock_mutex; 143182876Smarius lockfuncarg = &nsc->sc_lock; 144227302Smarius sc->sc_maxdmasize = nsc->sc_maxxfer; 145130293Sscottl sc->intr = lsi64854_scsi_intr; 146130293Sscottl sc->setup = lsi64854_setup; 147130293Sscottl break; 148130293Sscottl case L64854_CHANNEL_ENET: 149130293Sscottl sc->intr = lsi64854_enet_intr; 150130293Sscottl break; 151130293Sscottl case L64854_CHANNEL_PP: 152155089Smarius sc->intr = lsi64854_pp_intr; 153130293Sscottl sc->setup = lsi64854_setup_pp; 154130293Sscottl break; 155130293Sscottl default: 156145200Smarius device_printf(sc->sc_dev, "unknown channel\n"); 157130293Sscottl } 158130293Sscottl sc->reset = lsi64854_reset; 159130293Sscottl 160182876Smarius if (sc->setup != NULL) { 161182876Smarius error = bus_dma_tag_create( 162182876Smarius sc->sc_parent_dmat, /* parent */ 163227302Smarius 1, BOUNDARY, /* alignment, boundary */ 164227302Smarius BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 165182876Smarius BUS_SPACE_MAXADDR, /* highaddr */ 166182876Smarius NULL, NULL, /* filter, filterarg */ 167227302Smarius sc->sc_maxdmasize, /* maxsize */ 168182876Smarius 1, /* nsegments */ 169227302Smarius sc->sc_maxdmasize, /* maxsegsize */ 170182876Smarius BUS_DMA_ALLOCNOW, /* flags */ 171182876Smarius lockfunc, lockfuncarg, /* lockfunc, lockfuncarg */ 172182876Smarius &sc->sc_buffer_dmat); 173182876Smarius if (error != 0) { 174182876Smarius device_printf(sc->sc_dev, 175182876Smarius "cannot allocate buffer DMA tag\n"); 176182876Smarius return (error); 177182876Smarius } 178130293Sscottl 179182876Smarius error = bus_dmamap_create(sc->sc_buffer_dmat, 0, 180182876Smarius &sc->sc_dmamap); 181182876Smarius if (error != 0) { 182182876Smarius device_printf(sc->sc_dev, "DMA map create failed\n"); 183182876Smarius bus_dma_tag_destroy(sc->sc_buffer_dmat); 184182876Smarius return (error); 185182876Smarius } 186130293Sscottl } 187130293Sscottl 188130293Sscottl csr = L64854_GCSR(sc); 189130293Sscottl sc->sc_rev = csr & L64854_DEVID; 190145200Smarius if (sc->sc_rev == DMAREV_HME) 191146392Smarius return (0); 192145200Smarius device_printf(sc->sc_dev, "DMA rev. "); 193130293Sscottl switch (sc->sc_rev) { 194130293Sscottl case DMAREV_0: 195130293Sscottl printf("0"); 196130293Sscottl break; 197130293Sscottl case DMAREV_ESC: 198146392Smarius printf("ESC"); 199130293Sscottl break; 200130293Sscottl case DMAREV_1: 201130293Sscottl printf("1"); 202130293Sscottl break; 203130293Sscottl case DMAREV_PLUS: 204130293Sscottl printf("1+"); 205130293Sscottl break; 206130293Sscottl case DMAREV_2: 207130293Sscottl printf("2"); 208130293Sscottl break; 209130293Sscottl default: 210130293Sscottl printf("unknown (0x%x)", sc->sc_rev); 211130293Sscottl } 212130293Sscottl 213130293Sscottl DPRINTF(LDB_ANY, (", burst 0x%x, csr 0x%x", sc->sc_burst, csr)); 214130293Sscottl printf("\n"); 215146392Smarius 216146392Smarius return (0); 217130293Sscottl} 218130293Sscottl 219146392Smariusint 220146392Smariuslsi64854_detach(struct lsi64854_softc *sc) 221146392Smarius{ 222146392Smarius 223182876Smarius if (sc->setup != NULL) { 224182876Smarius bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, 225182876Smarius (L64854_GCSR(sc) & L64854_WRITE) != 0 ? 226182876Smarius BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 227146392Smarius bus_dmamap_unload(sc->sc_buffer_dmat, sc->sc_dmamap); 228182876Smarius bus_dmamap_destroy(sc->sc_buffer_dmat, sc->sc_dmamap); 229182876Smarius bus_dma_tag_destroy(sc->sc_buffer_dmat); 230182876Smarius } 231146392Smarius 232146392Smarius return (0); 233146392Smarius} 234146392Smarius 235130293Sscottl/* 236182876Smarius * DMAWAIT waits while condition is true. 237130293Sscottl */ 238130293Sscottl#define DMAWAIT(SC, COND, MSG, DONTPANIC) do if (COND) { \ 239130293Sscottl int count = 500000; \ 240130293Sscottl while ((COND) && --count > 0) DELAY(1); \ 241130293Sscottl if (count == 0) { \ 242130293Sscottl printf("%s: line %d: CSR = 0x%lx\n", __FILE__, __LINE__, \ 243130293Sscottl (u_long)L64854_GCSR(SC)); \ 244130293Sscottl if (DONTPANIC) \ 245130293Sscottl printf(MSG); \ 246130293Sscottl else \ 247130293Sscottl panic(MSG); \ 248130293Sscottl } \ 249226917Smarius} while (/* CONSTCOND */0) 250130293Sscottl 251130293Sscottl#define DMA_DRAIN(sc, dontpanic) do { \ 252145190Smarius uint32_t csr; \ 253130293Sscottl /* \ 254130293Sscottl * DMA rev0 & rev1: we are not allowed to touch the DMA "flush" \ 255130293Sscottl * and "drain" bits while it is still thinking about a \ 256130293Sscottl * request. \ 257130293Sscottl * other revs: D_ESC_R_PEND bit reads as 0 \ 258130293Sscottl */ \ 259130293Sscottl DMAWAIT(sc, L64854_GCSR(sc) & D_ESC_R_PEND, "R_PEND", dontpanic);\ 260227302Smarius if (sc->sc_rev != DMAREV_HME) { \ 261227302Smarius /* \ 262227302Smarius * Select drain bit based on revision \ 263227302Smarius * also clears errors and D_TC flag \ 264227302Smarius */ \ 265227302Smarius csr = L64854_GCSR(sc); \ 266227302Smarius if (sc->sc_rev == DMAREV_1 || sc->sc_rev == DMAREV_0) \ 267227302Smarius csr |= D_ESC_DRAIN; \ 268227302Smarius else \ 269227302Smarius csr |= L64854_INVALIDATE; \ 270130293Sscottl \ 271227302Smarius L64854_SCSR(sc, csr); \ 272130293Sscottl } \ 273130293Sscottl /* \ 274130293Sscottl * Wait for draining to finish \ 275145190Smarius * rev0 & rev1 call this PACKCNT \ 276130293Sscottl */ \ 277227302Smarius DMAWAIT(sc, L64854_GCSR(sc) & L64854_DRAINING, "DRAINING", \ 278227302Smarius dontpanic); \ 279226917Smarius} while (/* CONSTCOND */0) 280130293Sscottl 281130293Sscottl#define DMA_FLUSH(sc, dontpanic) do { \ 282145190Smarius uint32_t csr; \ 283130293Sscottl /* \ 284130293Sscottl * DMA rev0 & rev1: we are not allowed to touch the DMA "flush" \ 285130293Sscottl * and "drain" bits while it is still thinking about a \ 286130293Sscottl * request. \ 287130293Sscottl * other revs: D_ESC_R_PEND bit reads as 0 \ 288130293Sscottl */ \ 289130293Sscottl DMAWAIT(sc, L64854_GCSR(sc) & D_ESC_R_PEND, "R_PEND", dontpanic);\ 290130293Sscottl csr = L64854_GCSR(sc); \ 291130293Sscottl csr &= ~(L64854_WRITE|L64854_EN_DMA); /* no-ops on ENET */ \ 292130293Sscottl csr |= L64854_INVALIDATE; /* XXX FAS ? */ \ 293227302Smarius L64854_SCSR(sc, csr); \ 294226917Smarius} while (/* CONSTCOND */0) 295130293Sscottl 296155089Smariusstatic void 297130293Sscottllsi64854_reset(struct lsi64854_softc *sc) 298130293Sscottl{ 299227302Smarius bus_dma_tag_t dmat; 300227302Smarius bus_dmamap_t dmam; 301145190Smarius uint32_t csr; 302130293Sscottl 303130293Sscottl DMA_FLUSH(sc, 1); 304130293Sscottl csr = L64854_GCSR(sc); 305130293Sscottl 306145200Smarius DPRINTF(LDB_ANY, ("%s: csr 0x%x\n", __func__, csr)); 307130293Sscottl 308182876Smarius if (sc->sc_dmasize != 0) { 309227302Smarius dmat = sc->sc_buffer_dmat; 310227302Smarius dmam = sc->sc_dmamap; 311227302Smarius bus_dmamap_sync(dmat, dmam, (csr & D_WRITE) != 0 ? 312227302Smarius BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 313227302Smarius bus_dmamap_unload(dmat, dmam); 314182876Smarius } 315130293Sscottl 316130293Sscottl if (sc->sc_rev == DMAREV_HME) 317130293Sscottl L64854_SCSR(sc, csr | D_HW_RESET_FAS366); 318130293Sscottl 319130293Sscottl csr |= L64854_RESET; /* reset DMA */ 320130293Sscottl L64854_SCSR(sc, csr); 321130293Sscottl DELAY(200); /* > 10 Sbus clocks(?) */ 322130293Sscottl 323130293Sscottl /*DMAWAIT1(sc); why was this here? */ 324130293Sscottl csr = L64854_GCSR(sc); 325130293Sscottl csr &= ~L64854_RESET; /* de-assert reset line */ 326130293Sscottl L64854_SCSR(sc, csr); 327130293Sscottl DELAY(5); /* allow a few ticks to settle */ 328130293Sscottl 329130293Sscottl csr = L64854_GCSR(sc); 330130293Sscottl csr |= L64854_INT_EN; /* enable interrupts */ 331130293Sscottl if (sc->sc_rev > DMAREV_1 && sc->sc_channel == L64854_CHANNEL_SCSI) { 332130293Sscottl if (sc->sc_rev == DMAREV_HME) 333130293Sscottl csr |= D_TWO_CYCLE; 334130293Sscottl else 335130293Sscottl csr |= D_FASTER; 336130293Sscottl } 337130293Sscottl 338130293Sscottl /* Set burst */ 339130293Sscottl switch (sc->sc_rev) { 340130293Sscottl case DMAREV_HME: 341130293Sscottl case DMAREV_2: 342130293Sscottl csr &= ~L64854_BURST_SIZE; 343145200Smarius if (sc->sc_burst == 32) 344130293Sscottl csr |= L64854_BURST_32; 345145200Smarius else if (sc->sc_burst == 16) 346130293Sscottl csr |= L64854_BURST_16; 347145200Smarius else 348130293Sscottl csr |= L64854_BURST_0; 349130293Sscottl break; 350130293Sscottl case DMAREV_ESC: 351130293Sscottl csr |= D_ESC_AUTODRAIN; /* Auto-drain */ 352145200Smarius if (sc->sc_burst == 32) 353130293Sscottl csr &= ~D_ESC_BURST; 354145200Smarius else 355130293Sscottl csr |= D_ESC_BURST; 356130293Sscottl break; 357130293Sscottl default: 358130293Sscottl break; 359130293Sscottl } 360130293Sscottl L64854_SCSR(sc, csr); 361130293Sscottl 362130293Sscottl if (sc->sc_rev == DMAREV_HME) { 363182876Smarius bus_write_4(sc->sc_res, L64854_REG_ADDR, 0); 364130293Sscottl sc->sc_dmactl = csr; 365130293Sscottl } 366130293Sscottl sc->sc_active = 0; 367130293Sscottl 368145200Smarius DPRINTF(LDB_ANY, ("%s: done, csr 0x%x\n", __func__, csr)); 369130293Sscottl} 370130293Sscottl 371130293Sscottlstatic void 372130293Sscottllsi64854_map_scsi(void *arg, bus_dma_segment_t *segs, int nseg, int error) 373130293Sscottl{ 374130293Sscottl struct lsi64854_softc *sc; 375130293Sscottl 376130293Sscottl sc = (struct lsi64854_softc *)arg; 377130293Sscottl 378227302Smarius if (error != 0) 379227302Smarius return; 380130293Sscottl if (nseg != 1) 381145200Smarius panic("%s: cannot map %d segments\n", __func__, nseg); 382130293Sscottl 383145200Smarius bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, 384227302Smarius sc->sc_datain != 0 ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 385182876Smarius bus_write_4(sc->sc_res, L64854_REG_ADDR, segs[0].ds_addr); 386130293Sscottl} 387130293Sscottl 388130293Sscottl/* 389130293Sscottl * setup a DMA transfer 390130293Sscottl */ 391155089Smariusstatic int 392226917Smariuslsi64854_setup(struct lsi64854_softc *sc, void **addr, size_t *len, 393145200Smarius int datain, size_t *dmasize) 394130293Sscottl{ 395155089Smarius long bcnt; 396227302Smarius int error; 397145190Smarius uint32_t csr; 398130293Sscottl 399130293Sscottl DMA_FLUSH(sc, 0); 400130293Sscottl 401130293Sscottl#if 0 402130293Sscottl DMACSR(sc) &= ~D_INT_EN; 403130293Sscottl#endif 404130293Sscottl sc->sc_dmaaddr = addr; 405130293Sscottl sc->sc_dmalen = len; 406130293Sscottl sc->sc_datain = datain; 407130293Sscottl 408227302Smarius KASSERT(*dmasize <= sc->sc_maxdmasize, 409227302Smarius ("%s: transfer size %ld too large", __func__, (long)*dmasize)); 410130293Sscottl 411227302Smarius sc->sc_dmasize = *dmasize; 412130293Sscottl 413227302Smarius DPRINTF(LDB_ANY, ("%s: dmasize=%ld\n", __func__, (long)*dmasize)); 414227302Smarius 415130293Sscottl /* 416145200Smarius * XXX what length? 417130293Sscottl */ 418130293Sscottl if (sc->sc_rev == DMAREV_HME) { 419130293Sscottl L64854_SCSR(sc, sc->sc_dmactl | L64854_RESET); 420130293Sscottl L64854_SCSR(sc, sc->sc_dmactl); 421130293Sscottl 422182876Smarius bus_write_4(sc->sc_res, L64854_REG_CNT, *dmasize); 423130293Sscottl } 424130293Sscottl 425227302Smarius /* 426227302Smarius * Load the transfer buffer and program the DMA address. 427227302Smarius * Note that the NCR53C9x core can't handle EINPROGRESS so we set 428227302Smarius * BUS_DMA_NOWAIT. 429227302Smarius */ 430227302Smarius if (*dmasize != 0) { 431227302Smarius error = bus_dmamap_load(sc->sc_buffer_dmat, sc->sc_dmamap, 432227302Smarius *sc->sc_dmaaddr, *dmasize, lsi64854_map_scsi, sc, 433227302Smarius BUS_DMA_NOWAIT); 434227302Smarius if (error != 0) 435227302Smarius return (error); 436227302Smarius } 437130293Sscottl 438130293Sscottl if (sc->sc_rev == DMAREV_ESC) { 439130293Sscottl /* DMA ESC chip bug work-around */ 440227302Smarius bcnt = *dmasize; 441155089Smarius if (((bcnt + (long)*sc->sc_dmaaddr) & PAGE_MASK_8K) != 0) 442130293Sscottl bcnt = roundup(bcnt, PAGE_SIZE_8K); 443182876Smarius bus_write_4(sc->sc_res, L64854_REG_CNT, bcnt); 444130293Sscottl } 445130293Sscottl 446227302Smarius /* Setup the DMA control register. */ 447130293Sscottl csr = L64854_GCSR(sc); 448130293Sscottl 449227302Smarius if (datain != 0) 450130293Sscottl csr |= L64854_WRITE; 451130293Sscottl else 452130293Sscottl csr &= ~L64854_WRITE; 453130293Sscottl csr |= L64854_INT_EN; 454130293Sscottl 455145200Smarius if (sc->sc_rev == DMAREV_HME) 456130293Sscottl csr |= (D_DSBL_SCSI_DRN | D_EN_DMA); 457130293Sscottl 458130293Sscottl L64854_SCSR(sc, csr); 459130293Sscottl 460130293Sscottl return (0); 461130293Sscottl} 462130293Sscottl 463130293Sscottl/* 464130293Sscottl * Pseudo (chained) interrupt from the esp driver to kick the 465227302Smarius * current running DMA transfer. Called from ncr53c9x_intr() 466130293Sscottl * for now. 467130293Sscottl * 468130293Sscottl * return 1 if it was a DMA continue. 469130293Sscottl */ 470155089Smariusstatic int 471130293Sscottllsi64854_scsi_intr(void *arg) 472130293Sscottl{ 473130293Sscottl struct lsi64854_softc *sc = arg; 474130293Sscottl struct ncr53c9x_softc *nsc = sc->sc_client; 475227302Smarius bus_dma_tag_t dmat; 476227302Smarius bus_dmamap_t dmam; 477227302Smarius size_t dmasize; 478227302Smarius int lxfer, resid, trans; 479145190Smarius uint32_t csr; 480130293Sscottl 481130293Sscottl csr = L64854_GCSR(sc); 482130293Sscottl 483145200Smarius DPRINTF(LDB_SCSI, ("%s: addr 0x%x, csr %b\n", __func__, 484227302Smarius bus_read_4(sc->sc_res, L64854_REG_ADDR), csr, DDMACSR_BITS)); 485130293Sscottl 486227302Smarius if (csr & (D_ERR_PEND | D_SLAVE_ERR)) { 487227302Smarius device_printf(sc->sc_dev, "error: csr=%b\n", csr, 488227302Smarius DDMACSR_BITS); 489227302Smarius csr &= ~D_EN_DMA; /* Stop DMA. */ 490130293Sscottl /* Invalidate the queue; SLAVE_ERR bit is write-to-clear */ 491227302Smarius csr |= D_INVALIDATE | D_SLAVE_ERR; 492130293Sscottl L64854_SCSR(sc, csr); 493130293Sscottl return (-1); 494130293Sscottl } 495130293Sscottl 496130293Sscottl /* This is an "assertion" :) */ 497130293Sscottl if (sc->sc_active == 0) 498145200Smarius panic("%s: DMA wasn't active", __func__); 499130293Sscottl 500130293Sscottl DMA_DRAIN(sc, 0); 501130293Sscottl 502130293Sscottl /* DMA has stopped */ 503130293Sscottl csr &= ~D_EN_DMA; 504130293Sscottl L64854_SCSR(sc, csr); 505130293Sscottl sc->sc_active = 0; 506130293Sscottl 507227302Smarius dmasize = sc->sc_dmasize; 508227302Smarius if (dmasize == 0) { 509227302Smarius /* A "Transfer Pad" operation completed. */ 510227302Smarius DPRINTF(LDB_SCSI, ("%s: discarded %d bytes (tcl=%d, " 511227302Smarius "tcm=%d)\n", __func__, NCR_READ_REG(nsc, NCR_TCL) | 512145200Smarius (NCR_READ_REG(nsc, NCR_TCM) << 8), 513145200Smarius NCR_READ_REG(nsc, NCR_TCL), NCR_READ_REG(nsc, NCR_TCM))); 514145200Smarius return (0); 515130293Sscottl } 516130293Sscottl 517130293Sscottl resid = 0; 518130293Sscottl /* 519130293Sscottl * If a transfer onto the SCSI bus gets interrupted by the device 520130293Sscottl * (e.g. for a SAVEPOINTER message), the data in the FIFO counts 521130293Sscottl * as residual since the NCR53C9X counter registers get decremented 522130293Sscottl * as bytes are clocked into the FIFO. 523130293Sscottl */ 524227302Smarius if ((csr & D_WRITE) == 0 && 525130293Sscottl (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 526145200Smarius DPRINTF(LDB_SCSI, ("%s: empty esp FIFO of %d ", __func__, 527145200Smarius resid)); 528130293Sscottl if (nsc->sc_rev == NCR_VARIANT_FAS366 && 529130293Sscottl (NCR_READ_REG(nsc, NCR_CFG3) & NCRFASCFG3_EWIDE)) 530130293Sscottl resid <<= 1; 531130293Sscottl } 532130293Sscottl 533130293Sscottl if ((nsc->sc_espstat & NCRSTAT_TC) == 0) { 534227302Smarius lxfer = nsc->sc_features & NCR_F_LARGEXFER; 535130293Sscottl /* 536227302Smarius * "Terminal count" is off, so read the residue 537130293Sscottl * out of the NCR53C9X counter registers. 538130293Sscottl */ 539130293Sscottl resid += (NCR_READ_REG(nsc, NCR_TCL) | 540145200Smarius (NCR_READ_REG(nsc, NCR_TCM) << 8) | 541227302Smarius (lxfer != 0 ? (NCR_READ_REG(nsc, NCR_TCH) << 16) : 0)); 542130293Sscottl 543227302Smarius if (resid == 0 && dmasize == 65536 && lxfer == 0) 544227302Smarius /* A transfer of 64k is encoded as TCL=TCM=0. */ 545130293Sscottl resid = 65536; 546130293Sscottl } 547130293Sscottl 548227302Smarius trans = dmasize - resid; 549220939Smarius if (trans < 0) { /* transferred < 0? */ 550130293Sscottl#if 0 551130293Sscottl /* 552130293Sscottl * This situation can happen in perfectly normal operation 553130293Sscottl * if the ESP is reselected while using DMA to select 554130293Sscottl * another target. As such, don't print the warning. 555130293Sscottl */ 556145200Smarius device_printf(sc->sc_dev, "xfer (%d) > req (%d)\n", trans, 557227302Smarius dmasize); 558130293Sscottl#endif 559227302Smarius trans = dmasize; 560130293Sscottl } 561130293Sscottl 562145200Smarius DPRINTF(LDB_SCSI, ("%s: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", 563145200Smarius __func__, NCR_READ_REG(nsc, NCR_TCL), NCR_READ_REG(nsc, NCR_TCM), 564227718Smarius (nsc->sc_features & NCR_F_LARGEXFER) != 0 ? 565227302Smarius NCR_READ_REG(nsc, NCR_TCH) : 0, trans, resid)); 566130293Sscottl 567227302Smarius if (dmasize != 0) { 568227302Smarius dmat = sc->sc_buffer_dmat; 569227302Smarius dmam = sc->sc_dmamap; 570227302Smarius bus_dmamap_sync(dmat, dmam, (csr & D_WRITE) != 0 ? 571227302Smarius BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 572227302Smarius bus_dmamap_unload(dmat, dmam); 573130293Sscottl } 574130293Sscottl 575130293Sscottl *sc->sc_dmalen -= trans; 576226917Smarius *sc->sc_dmaaddr = (char *)*sc->sc_dmaaddr + trans; 577130293Sscottl 578130293Sscottl#if 0 /* this is not normal operation just yet */ 579145200Smarius if (*sc->sc_dmalen == 0 || nsc->sc_phase != nsc->sc_prevphase) 580145200Smarius return (0); 581130293Sscottl 582130293Sscottl /* and again */ 583130293Sscottl dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE); 584145200Smarius return (1); 585130293Sscottl#endif 586145200Smarius return (0); 587130293Sscottl} 588130293Sscottl 589130293Sscottl/* 590227302Smarius * Pseudo (chained) interrupt to le(4) driver to handle DMA errors 591130293Sscottl */ 592155089Smariusstatic int 593130293Sscottllsi64854_enet_intr(void *arg) 594130293Sscottl{ 595130293Sscottl struct lsi64854_softc *sc = arg; 596145190Smarius uint32_t csr; 597155089Smarius int i, rv; 598130293Sscottl 599130293Sscottl csr = L64854_GCSR(sc); 600130293Sscottl 601130293Sscottl /* If the DMA logic shows an interrupt, claim it */ 602130293Sscottl rv = ((csr & E_INT_PEND) != 0) ? 1 : 0; 603130293Sscottl 604227302Smarius if (csr & (E_ERR_PEND | E_SLAVE_ERR)) { 605227302Smarius device_printf(sc->sc_dev, "error: csr=%b\n", csr, 606227302Smarius EDMACSR_BITS); 607227302Smarius csr &= ~L64854_EN_DMA; /* Stop DMA. */ 608130293Sscottl /* Invalidate the queue; SLAVE_ERR bit is write-to-clear */ 609227302Smarius csr |= E_INVALIDATE | E_SLAVE_ERR; 610130293Sscottl L64854_SCSR(sc, csr); 611155089Smarius /* Will be drained with the LE_C0_IDON interrupt. */ 612155089Smarius sc->sc_dodrain = 1; 613155089Smarius return (-1); 614130293Sscottl } 615130293Sscottl 616155089Smarius /* XXX - is this necessary with E_DSBL_WR_INVAL on? */ 617155089Smarius if (sc->sc_dodrain) { 618155089Smarius i = 10; 619130293Sscottl csr |= E_DRAIN; 620130293Sscottl L64854_SCSR(sc, csr); 621155089Smarius while (i-- > 0 && (L64854_GCSR(sc) & E_DRAINING)) 622130293Sscottl DELAY(1); 623155089Smarius sc->sc_dodrain = 0; 624130293Sscottl } 625130293Sscottl 626146392Smarius return (rv); 627130293Sscottl} 628130293Sscottl 629130293Sscottlstatic void 630130293Sscottllsi64854_map_pp(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 631130293Sscottl{ 632130293Sscottl struct lsi64854_softc *sc; 633130293Sscottl 634130293Sscottl sc = (struct lsi64854_softc *)arg; 635130293Sscottl 636227302Smarius if (error != 0) 637227302Smarius return; 638130293Sscottl if (nsegs != 1) 639145200Smarius panic("%s: cannot map %d segments\n", __func__, nsegs); 640130293Sscottl 641227302Smarius bus_dmamap_sync(sc->sc_buffer_dmat, sc->sc_dmamap, 642227302Smarius sc->sc_datain != 0 ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 643182876Smarius bus_write_4(sc->sc_res, L64854_REG_ADDR, segs[0].ds_addr); 644130293Sscottl 645182876Smarius bus_write_4(sc->sc_res, L64854_REG_CNT, sc->sc_dmasize); 646130293Sscottl} 647130293Sscottl 648130293Sscottl/* 649227302Smarius * Setup a DMA transfer. 650130293Sscottl */ 651155089Smariusstatic int 652226917Smariuslsi64854_setup_pp(struct lsi64854_softc *sc, void **addr, size_t *len, 653145200Smarius int datain, size_t *dmasize) 654130293Sscottl{ 655227302Smarius int error; 656145190Smarius uint32_t csr; 657130293Sscottl 658130293Sscottl DMA_FLUSH(sc, 0); 659130293Sscottl 660130293Sscottl sc->sc_dmaaddr = addr; 661130293Sscottl sc->sc_dmalen = len; 662130293Sscottl sc->sc_datain = datain; 663130293Sscottl 664145200Smarius DPRINTF(LDB_PP, ("%s: pp start %ld@%p,%d\n", __func__, 665227302Smarius (long)*sc->sc_dmalen, *sc->sc_dmaaddr, datain != 0 ? 1 : 0)); 666130293Sscottl 667227302Smarius KASSERT(*dmasize <= sc->sc_maxdmasize, 668227302Smarius ("%s: transfer size %ld too large", __func__, (long)*dmasize)); 669130293Sscottl 670227302Smarius sc->sc_dmasize = *dmasize; 671130293Sscottl 672227302Smarius DPRINTF(LDB_PP, ("%s: dmasize=%ld\n", __func__, (long)*dmasize)); 673130293Sscottl 674227302Smarius /* Load the transfer buffer and program the DMA address. */ 675227302Smarius if (*dmasize != 0) { 676227302Smarius error = bus_dmamap_load(sc->sc_buffer_dmat, sc->sc_dmamap, 677227302Smarius *sc->sc_dmaaddr, *dmasize, lsi64854_map_pp, sc, 678227302Smarius BUS_DMA_NOWAIT); 679227302Smarius if (error != 0) 680227302Smarius return (error); 681227302Smarius } 682227302Smarius 683227302Smarius /* Setup the DMA control register. */ 684130293Sscottl csr = L64854_GCSR(sc); 685130293Sscottl csr &= ~L64854_BURST_SIZE; 686145200Smarius if (sc->sc_burst == 32) 687130293Sscottl csr |= L64854_BURST_32; 688145200Smarius else if (sc->sc_burst == 16) 689130293Sscottl csr |= L64854_BURST_16; 690145200Smarius else 691130293Sscottl csr |= L64854_BURST_0; 692227302Smarius csr |= P_EN_DMA | P_INT_EN | P_EN_CNT; 693130293Sscottl#if 0 694227302Smarius /* This bit is read-only in PP csr register. */ 695227302Smarius if (datain != 0) 696130293Sscottl csr |= P_WRITE; 697130293Sscottl else 698130293Sscottl csr &= ~P_WRITE; 699130293Sscottl#endif 700130293Sscottl L64854_SCSR(sc, csr); 701130293Sscottl 702130293Sscottl return (0); 703130293Sscottl} 704145200Smarius 705130293Sscottl/* 706227302Smarius * Parallel port DMA interrupt 707130293Sscottl */ 708155089Smariusstatic int 709130293Sscottllsi64854_pp_intr(void *arg) 710130293Sscottl{ 711130293Sscottl struct lsi64854_softc *sc = arg; 712227302Smarius bus_dma_tag_t dmat; 713227302Smarius bus_dmamap_t dmam; 714227302Smarius size_t dmasize; 715130293Sscottl int ret, trans, resid = 0; 716145190Smarius uint32_t csr; 717130293Sscottl 718130293Sscottl csr = L64854_GCSR(sc); 719130293Sscottl 720145200Smarius DPRINTF(LDB_PP, ("%s: addr 0x%x, csr %b\n", __func__, 721182876Smarius bus_read_4(sc->sc_res, L64854_REG_ADDR), csr, PDMACSR_BITS)); 722130293Sscottl 723227302Smarius if ((csr & (P_ERR_PEND | P_SLAVE_ERR)) != 0) { 724182876Smarius resid = bus_read_4(sc->sc_res, L64854_REG_CNT); 725145200Smarius device_printf(sc->sc_dev, "error: resid %d csr=%b\n", resid, 726145200Smarius csr, PDMACSR_BITS); 727227302Smarius csr &= ~P_EN_DMA; /* Stop DMA. */ 728130293Sscottl /* Invalidate the queue; SLAVE_ERR bit is write-to-clear */ 729227302Smarius csr |= P_INVALIDATE | P_SLAVE_ERR; 730130293Sscottl L64854_SCSR(sc, csr); 731155089Smarius return (-1); 732130293Sscottl } 733130293Sscottl 734130293Sscottl ret = (csr & P_INT_PEND) != 0; 735130293Sscottl 736130293Sscottl if (sc->sc_active != 0) { 737130293Sscottl DMA_DRAIN(sc, 0); 738182876Smarius resid = bus_read_4(sc->sc_res, L64854_REG_CNT); 739130293Sscottl } 740130293Sscottl 741130293Sscottl /* DMA has stopped */ 742130293Sscottl csr &= ~D_EN_DMA; 743130293Sscottl L64854_SCSR(sc, csr); 744130293Sscottl sc->sc_active = 0; 745130293Sscottl 746227302Smarius dmasize = sc->sc_dmasize; 747227302Smarius trans = dmasize - resid; 748220939Smarius if (trans < 0) /* transferred < 0? */ 749227302Smarius trans = dmasize; 750130293Sscottl *sc->sc_dmalen -= trans; 751226917Smarius *sc->sc_dmaaddr = (char *)*sc->sc_dmaaddr + trans; 752130293Sscottl 753227302Smarius if (dmasize != 0) { 754227302Smarius dmat = sc->sc_buffer_dmat; 755227302Smarius dmam = sc->sc_dmamap; 756227302Smarius bus_dmamap_sync(dmat, dmam, (csr & D_WRITE) != 0 ? 757227302Smarius BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 758227302Smarius bus_dmamap_unload(dmat, dmam); 759130293Sscottl } 760130293Sscottl 761130293Sscottl return (ret != 0); 762130293Sscottl} 763