Annotation of sys/arch/mac68k/dev/sbc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sbc.c,v 1.16 2006/12/13 21:12:56 miod Exp $ */
! 2: /* $NetBSD: sbc.c,v 1.24 1997/04/18 17:38:08 scottr Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1996 Scott Reynolds. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Scott Reynolds for
! 18: * the NetBSD Project.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: /*
! 35: * This file contains only the machine-dependent parts of the mac68k
! 36: * NCR 5380 SCSI driver. (Autoconfig stuff and PDMA functions.)
! 37: * The machine-independent parts are in ncr5380sbc.c
! 38: *
! 39: * Supported hardware includes:
! 40: * Macintosh II family 5380-based controller
! 41: *
! 42: * Credits, history:
! 43: *
! 44: * Scott Reynolds wrote this module, based on work by Allen Briggs
! 45: * (mac68k), Gordon W. Ross and David Jones (sun3), and Leo Weppelman
! 46: * (atari). Thanks to Allen for supplying crucial interpretation of the
! 47: * NetBSD/mac68k 1.1 'ncrscsi' driver. Also, Allen, Gordon, and Jason
! 48: * Thorpe all helped to refine this code, and were considerable sources
! 49: * of moral support.
! 50: */
! 51:
! 52: #include <sys/types.h>
! 53: #include <sys/param.h>
! 54: #include <sys/systm.h>
! 55: #include <sys/kernel.h>
! 56: #include <sys/errno.h>
! 57: #include <sys/device.h>
! 58: #include <sys/buf.h>
! 59: #include <sys/proc.h>
! 60: #include <sys/user.h>
! 61:
! 62: #include <scsi/scsi_all.h>
! 63: #include <scsi/scsi_debug.h>
! 64: #include <scsi/scsiconf.h>
! 65:
! 66: #include <dev/ic/ncr5380reg.h>
! 67: #include <dev/ic/ncr5380var.h>
! 68:
! 69: #include <machine/cpu.h>
! 70: #include <machine/viareg.h>
! 71:
! 72: #include "sbcreg.h"
! 73: #include "sbcvar.h"
! 74:
! 75: int sbc_debug = 0 /* | SBC_DB_INTR | SBC_DB_DMA */;
! 76: int sbc_link_flags = 0 /* | SDEV_DB2 */;
! 77: int sbc_options = 0 /* | SBC_PDMA */;
! 78:
! 79: static void sbc_minphys(struct buf *bp);
! 80:
! 81: struct scsi_adapter sbc_ops = {
! 82: ncr5380_scsi_cmd, /* scsi_cmd() */
! 83: sbc_minphys, /* scsi_minphys() */
! 84: NULL, /* open_target_lu() */
! 85: NULL, /* close_target_lu() */
! 86: };
! 87:
! 88: /* This is copied from julian's bt driver */
! 89: /* "so we have a default dev struct for our link struct." */
! 90: struct scsi_device sbc_dev = {
! 91: NULL, /* Use default error handler. */
! 92: NULL, /* Use default start handler. */
! 93: NULL, /* Use default async handler. */
! 94: NULL, /* Use default "done" routine. */
! 95: };
! 96:
! 97: struct cfdriver sbc_cd = {
! 98: NULL, "sbc", DV_DULL
! 99: };
! 100:
! 101: static int sbc_ready(struct ncr5380_softc *);
! 102: static void sbc_wait_not_req(struct ncr5380_softc *);
! 103:
! 104: static void
! 105: sbc_minphys(struct buf *bp)
! 106: {
! 107: if (bp->b_bcount > MAX_DMA_LEN)
! 108: bp->b_bcount = MAX_DMA_LEN;
! 109: return (minphys(bp));
! 110: }
! 111:
! 112:
! 113: /***
! 114: * General support for Mac-specific SCSI logic.
! 115: ***/
! 116:
! 117: int
! 118: sbc_irq_intr(p)
! 119: void *p;
! 120: {
! 121: struct ncr5380_softc *ncr_sc = p;
! 122: int claimed = 0;
! 123:
! 124: /* How we ever arrive here without IRQ set is a mystery... */
! 125: if (*ncr_sc->sci_csr & SCI_CSR_INT) {
! 126: #ifdef SBC_DEBUG
! 127: if (sbc_debug & SBC_DB_INTR)
! 128: decode_5380_intr(ncr_sc);
! 129: #endif
! 130: claimed = ncr5380_intr(ncr_sc);
! 131: if (!claimed) {
! 132: if (((*ncr_sc->sci_csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT)
! 133: && ((*ncr_sc->sci_bus_csr & ~SCI_BUS_RST) == 0))
! 134: SCI_CLR_INTR(ncr_sc); /* RST interrupt */
! 135: #ifdef SBC_DEBUG
! 136: else {
! 137: printf("%s: spurious intr\n",
! 138: ncr_sc->sc_dev.dv_xname);
! 139: SBC_BREAK;
! 140: }
! 141: #endif
! 142: }
! 143: }
! 144:
! 145: return (claimed);
! 146: }
! 147:
! 148: #ifdef SBC_DEBUG
! 149: void
! 150: decode_5380_intr(ncr_sc)
! 151: struct ncr5380_softc *ncr_sc;
! 152: {
! 153: u_char csr = *ncr_sc->sci_csr;
! 154: u_char bus_csr = *ncr_sc->sci_bus_csr;
! 155:
! 156: if (((csr & ~(SCI_CSR_PHASE_MATCH | SCI_CSR_ATN)) == SCI_CSR_INT) &&
! 157: ((bus_csr & ~(SCI_BUS_MSG | SCI_BUS_CD | SCI_BUS_IO | SCI_BUS_DBP)) == SCI_BUS_SEL)) {
! 158: if (csr & SCI_BUS_IO)
! 159: printf("%s: reselect\n", ncr_sc->sc_dev.dv_xname);
! 160: else
! 161: printf("%s: select\n", ncr_sc->sc_dev.dv_xname);
! 162: } else if (((csr & ~SCI_CSR_ACK) == (SCI_CSR_DONE | SCI_CSR_INT)) &&
! 163: ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_SEL)) == SCI_BUS_BSY))
! 164: printf("%s: dma eop\n", ncr_sc->sc_dev.dv_xname);
! 165: else if (((csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT) &&
! 166: ((bus_csr & ~SCI_BUS_RST) == 0))
! 167: printf("%s: bus reset\n", ncr_sc->sc_dev.dv_xname);
! 168: else if (((csr & ~(SCI_CSR_DREQ | SCI_CSR_ATN | SCI_CSR_ACK)) == (SCI_CSR_PERR | SCI_CSR_INT | SCI_CSR_PHASE_MATCH)) &&
! 169: ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_SEL)) == SCI_BUS_BSY))
! 170: printf("%s: parity error\n", ncr_sc->sc_dev.dv_xname);
! 171: else if (((csr & ~SCI_CSR_ATN) == SCI_CSR_INT) &&
! 172: ((bus_csr & (SCI_BUS_RST | SCI_BUS_BSY | SCI_BUS_REQ | SCI_BUS_SEL)) == (SCI_BUS_BSY | SCI_BUS_REQ)))
! 173: printf("%s: phase mismatch\n", ncr_sc->sc_dev.dv_xname);
! 174: else if (((csr & ~SCI_CSR_PHASE_MATCH) == (SCI_CSR_INT | SCI_CSR_DISC)) &&
! 175: (bus_csr == 0))
! 176: printf("%s: disconnect\n", ncr_sc->sc_dev.dv_xname);
! 177: else
! 178: printf("%s: unknown intr: csr=%x, bus_csr=%x\n",
! 179: ncr_sc->sc_dev.dv_xname, csr, bus_csr);
! 180: }
! 181: #endif
! 182:
! 183:
! 184: /***
! 185: * The following code implements polled PDMA.
! 186: ***/
! 187:
! 188: #define TIMEOUT 5000000 /* x 2 usec = 10 sec */
! 189:
! 190: static __inline__ int
! 191: sbc_ready(sc)
! 192: struct ncr5380_softc *sc;
! 193: {
! 194: int i = TIMEOUT;
! 195:
! 196: for (;;) {
! 197: if ((*sc->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) ==
! 198: (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
! 199: return 1;
! 200: if (((*sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0) ||
! 201: (SCI_BUSY(sc) == 0))
! 202: return 0;
! 203: if (--i < 0)
! 204: break;
! 205: delay(2);
! 206: }
! 207:
! 208: printf("%s: ready timeout\n", sc->sc_dev.dv_xname);
! 209: return 0;
! 210: }
! 211:
! 212: static __inline__ void
! 213: sbc_wait_not_req(sc)
! 214: struct ncr5380_softc *sc;
! 215: {
! 216: int i = TIMEOUT;
! 217:
! 218: for (;;) {
! 219: if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0 ||
! 220: (*sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0 ||
! 221: SCI_BUSY(sc) == 0) {
! 222: return;
! 223: }
! 224: if (--i < 0)
! 225: break;
! 226: delay(2);
! 227: }
! 228: printf("%s: pdma not_req timeout\n", sc->sc_dev.dv_xname);
! 229: }
! 230:
! 231: int
! 232: sbc_pdma_in(ncr_sc, phase, datalen, data)
! 233: struct ncr5380_softc *ncr_sc;
! 234: int phase, datalen;
! 235: u_char *data;
! 236: {
! 237: struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 238: volatile u_int32_t *long_data = (u_int32_t *)sc->sc_drq_addr;
! 239: volatile u_int8_t *byte_data = (u_int8_t *)sc->sc_nodrq_addr;
! 240: int resid, s;
! 241:
! 242: s = splbio();
! 243: *ncr_sc->sci_mode |= SCI_MODE_DMA;
! 244: *ncr_sc->sci_irecv = 0;
! 245:
! 246: #define R4 *((u_int32_t *)data)++ = *long_data++
! 247: #define R1 *data++ = *byte_data++
! 248: for (resid = datalen; resid >= 128; resid -= 128) {
! 249: if (sbc_ready(ncr_sc) == 0)
! 250: goto interrupt;
! 251: R4; R4; R4; R4; R4; R4; R4; R4;
! 252: R4; R4; R4; R4; R4; R4; R4; R4;
! 253: R4; R4; R4; R4; R4; R4; R4; R4;
! 254: R4; R4; R4; R4; R4; R4; R4; R4;
! 255:
! 256: long_data = (u_int32_t *)sc->sc_drq_addr;
! 257: byte_data = (u_int8_t *)sc->sc_nodrq_addr;
! 258: }
! 259: while (resid) {
! 260: if (sbc_ready(ncr_sc) == 0)
! 261: goto interrupt;
! 262: R1;
! 263: resid--;
! 264: }
! 265: #undef R4
! 266: #undef R1
! 267:
! 268: sbc_wait_not_req(ncr_sc);
! 269: interrupt:
! 270: SCI_CLR_INTR(ncr_sc);
! 271: *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 272: splx(s);
! 273: return datalen - resid;
! 274: }
! 275:
! 276: int
! 277: sbc_pdma_out(ncr_sc, phase, datalen, data)
! 278: struct ncr5380_softc *ncr_sc;
! 279: int phase, datalen;
! 280: u_char *data;
! 281: {
! 282: struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 283: volatile u_int32_t *long_data = (u_int32_t *)sc->sc_drq_addr;
! 284: volatile u_int8_t *byte_data = (u_int8_t *)sc->sc_nodrq_addr;
! 285: int i, s, resid;
! 286: u_char icmd;
! 287:
! 288: if (datalen < 64)
! 289: return ncr5380_pio_out(ncr_sc, phase, datalen, data);
! 290:
! 291: s = splbio();
! 292: icmd = *(ncr_sc->sci_icmd) & SCI_ICMD_RMASK;
! 293: *ncr_sc->sci_icmd = icmd | SCI_ICMD_DATA;
! 294: *ncr_sc->sci_mode |= SCI_MODE_DMA;
! 295: *ncr_sc->sci_dma_send = 0;
! 296:
! 297: resid = datalen;
! 298: if (sbc_ready(ncr_sc) == 0)
! 299: goto interrupt;
! 300:
! 301: #define W1 *byte_data++ = *data++
! 302: #define W4 *long_data++ = *((u_int32_t *)data)++
! 303: while (resid >= 64) {
! 304: if (sbc_ready(ncr_sc) == 0)
! 305: goto interrupt;
! 306: W1;
! 307: resid--;
! 308: if (sbc_ready(ncr_sc) == 0)
! 309: goto interrupt;
! 310: W1;
! 311: resid--;
! 312: if (sbc_ready(ncr_sc) == 0)
! 313: goto interrupt;
! 314: W1;
! 315: resid--;
! 316: if (sbc_ready(ncr_sc) == 0)
! 317: goto interrupt;
! 318: W1;
! 319: resid--;
! 320: if (sbc_ready(ncr_sc) == 0)
! 321: goto interrupt;
! 322: W4; W4; W4; W4;
! 323: W4; W4; W4; W4;
! 324: W4; W4; W4; W4;
! 325: W4; W4; W4;
! 326: resid -= 60;
! 327:
! 328: long_data = (u_int32_t *)sc->sc_drq_addr;
! 329: byte_data = (u_int8_t *)sc->sc_nodrq_addr;
! 330: }
! 331: for (; resid; resid--) {
! 332: if (sbc_ready(ncr_sc) == 0)
! 333: goto interrupt;
! 334: W1;
! 335: }
! 336: #undef W1
! 337: #undef W4
! 338:
! 339: for (i = TIMEOUT; i > 0; i--) {
! 340: if ((*ncr_sc->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
! 341: != SCI_CSR_DREQ)
! 342: break;
! 343: }
! 344: if (i != 0)
! 345: *byte_data = 0;
! 346: else
! 347: printf("%s: timeout waiting for final SCI_DSR_DREQ.\n",
! 348: ncr_sc->sc_dev.dv_xname);
! 349:
! 350: sbc_wait_not_req(ncr_sc);
! 351: interrupt:
! 352: SCI_CLR_INTR(ncr_sc);
! 353: *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 354: *ncr_sc->sci_icmd = icmd;
! 355: splx(s);
! 356: return (datalen - resid);
! 357: }
! 358:
! 359:
! 360: /***
! 361: * The following code implements interrupt-driven PDMA.
! 362: ***/
! 363:
! 364: /*
! 365: * This is the meat of the PDMA transfer.
! 366: * When we get here, we shove data as fast as the mac can take it.
! 367: * We depend on several things:
! 368: * * All macs after the Mac Plus that have a 5380 chip should have a general
! 369: * logic IC that handshakes data for blind transfers.
! 370: * * If the SCSI controller finishes sending/receiving data before we do,
! 371: * the same general logic IC will generate a /BERR for us in short order.
! 372: * * The fault address for said /BERR minus the base address for the
! 373: * transfer will be the amount of data that was actually written.
! 374: *
! 375: * We use the nofault flag and the setjmp/longjmp in locore.s so we can
! 376: * detect and handle the bus error for early termination of a command.
! 377: * This is usually caused by a disconnecting target.
! 378: */
! 379: int
! 380: sbc_drq_intr(p)
! 381: void *p;
! 382: {
! 383: extern int *nofault, m68k_fault_addr;
! 384: struct sbc_softc *sc = (struct sbc_softc *)p;
! 385: struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *)p;
! 386: struct sci_req *sr = ncr_sc->sc_current;
! 387: struct sbc_pdma_handle *dh = sr->sr_dma_hand;
! 388: label_t faultbuf;
! 389: volatile u_int32_t *long_drq;
! 390: u_int32_t *long_data;
! 391: volatile u_int8_t *drq;
! 392: u_int8_t *data;
! 393: int count, dcount, resid;
! 394: #ifdef SBC_WRITE_HACK
! 395: u_int8_t tmp;
! 396: #endif
! 397:
! 398: /*
! 399: * If we're not ready to xfer data, or have no more, just return.
! 400: */
! 401: if ((*ncr_sc->sci_csr & SCI_CSR_DREQ) == 0 || dh->dh_len == 0)
! 402: return (0);
! 403:
! 404: #ifdef SBC_DEBUG
! 405: if (sbc_debug & SBC_DB_INTR)
! 406: printf("%s: drq intr, dh_len=0x%x, dh_flags=0x%x\n",
! 407: ncr_sc->sc_dev.dv_xname, dh->dh_len, dh->dh_flags);
! 408: #endif
! 409:
! 410: /*
! 411: * Setup for a possible bus error caused by SCSI controller
! 412: * switching out of DATA-IN/OUT before we're done with the
! 413: * current transfer.
! 414: */
! 415: nofault = (int *) &faultbuf;
! 416:
! 417: if (setjmp((label_t *)nofault)) {
! 418: nofault = (int *) 0;
! 419: if ((dh->dh_flags & SBC_DH_DONE) == 0) {
! 420: count = (( (u_long)m68k_fault_addr
! 421: - (u_long)sc->sc_drq_addr));
! 422:
! 423: if ((count < 0) || (count > dh->dh_len)) {
! 424: printf("%s: complete=0x%x (pending 0x%x)\n",
! 425: ncr_sc->sc_dev.dv_xname, count, dh->dh_len);
! 426: panic("something is wrong");
! 427: }
! 428:
! 429: dh->dh_addr += count;
! 430: dh->dh_len -= count;
! 431: } else
! 432: count = 0;
! 433:
! 434: #ifdef SBC_DEBUG
! 435: if (sbc_debug & SBC_DB_INTR)
! 436: printf("%s: drq /berr, complete=0x%x (pending 0x%x)\n",
! 437: ncr_sc->sc_dev.dv_xname, count, dh->dh_len);
! 438: #endif
! 439: m68k_fault_addr = 0;
! 440:
! 441: return (1);
! 442: }
! 443:
! 444: if (dh->dh_flags & SBC_DH_OUT) { /* Data Out */
! 445: #if notyet /* XXX */
! 446: /*
! 447: * Get the source address aligned.
! 448: */
! 449: resid =
! 450: count = min(dh->dh_len, 4 - (((int)dh->dh_addr) & 0x3));
! 451: if (count && count < 4) {
! 452: drq = (volatile u_int8_t *)sc->sc_drq_addr;
! 453: data = (u_int8_t *)dh->dh_addr;
! 454:
! 455: #define W1 *drq++ = *data++
! 456: while (count) {
! 457: W1; count--;
! 458: }
! 459: #undef W1
! 460: dh->dh_addr += resid;
! 461: dh->dh_len -= resid;
! 462: }
! 463:
! 464: /*
! 465: * Start the transfer.
! 466: */
! 467: while (dh->dh_len) {
! 468: dcount = count = min(dh->dh_len, MAX_DMA_LEN);
! 469: long_drq = (volatile u_int32_t *)sc->sc_drq_addr;
! 470: long_data = (u_int32_t *)dh->dh_addr;
! 471:
! 472: #define W4 *long_drq++ = *long_data++
! 473: while (count >= 64) {
! 474: W4; W4; W4; W4; W4; W4; W4; W4;
! 475: W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */
! 476: count -= 64;
! 477: }
! 478: while (count >= 4) {
! 479: W4; count -= 4;
! 480: }
! 481: #undef W4
! 482: data = (u_int8_t *)long_data;
! 483: drq = (u_int8_t *)long_drq;
! 484: #else /* notyet */
! 485: /*
! 486: * Start the transfer.
! 487: */
! 488: while (dh->dh_len) {
! 489: dcount = count = min(dh->dh_len, MAX_DMA_LEN);
! 490: drq = (volatile u_int8_t *)sc->sc_drq_addr;
! 491: data = (u_int8_t *)dh->dh_addr;
! 492: #endif /* notyet */
! 493:
! 494: #define W1 *drq++ = *data++
! 495: while (count) {
! 496: W1; count--;
! 497: }
! 498: #undef W1
! 499: dh->dh_len -= dcount;
! 500: dh->dh_addr += dcount;
! 501: }
! 502: dh->dh_flags |= SBC_DH_DONE;
! 503:
! 504: #ifdef SBC_WRITE_HACK
! 505: /*
! 506: * XXX -- Read a byte from the SBC to trigger a /BERR.
! 507: * This seems to be necessary for us to notice that
! 508: * the target has disconnected. Ick. 06 jun 1996 (sr)
! 509: */
! 510: if (dcount >= MAX_DMA_LEN) {
! 511: #if 0
! 512: while ((*ncr_sc->sci_csr & SCI_CSR_ACK) == 0)
! 513: ;
! 514: #endif
! 515: drq = (volatile u_int8_t *)sc->sc_drq_addr;
! 516: }
! 517: tmp = *drq;
! 518: #endif
! 519: } else { /* Data In */
! 520: /*
! 521: * Get the dest address aligned.
! 522: */
! 523: resid =
! 524: count = min(dh->dh_len, 4 - (((int)dh->dh_addr) & 0x3));
! 525: if (count && count < 4) {
! 526: data = (u_int8_t *)dh->dh_addr;
! 527: drq = (volatile u_int8_t *)sc->sc_drq_addr;
! 528:
! 529: #define R1 *data++ = *drq++
! 530: while (count) {
! 531: R1; count--;
! 532: }
! 533: #undef R1
! 534: dh->dh_addr += resid;
! 535: dh->dh_len -= resid;
! 536: }
! 537:
! 538: /*
! 539: * Start the transfer.
! 540: */
! 541: while (dh->dh_len) {
! 542: dcount = count = min(dh->dh_len, MAX_DMA_LEN);
! 543: long_data = (u_int32_t *)dh->dh_addr;
! 544: long_drq = (volatile u_int32_t *)sc->sc_drq_addr;
! 545:
! 546: #define R4 *long_data++ = *long_drq++
! 547: while (count >= 64) {
! 548: R4; R4; R4; R4; R4; R4; R4; R4;
! 549: R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */
! 550: count -= 64;
! 551: }
! 552: while (count >= 4) {
! 553: R4; count -= 4;
! 554: }
! 555: #undef R4
! 556: data = (u_int8_t *)long_data;
! 557: drq = (volatile u_int8_t *)long_drq;
! 558:
! 559: #define R1 *data++ = *drq++
! 560: while (count) {
! 561: R1; count--;
! 562: }
! 563: #undef R1
! 564: dh->dh_len -= dcount;
! 565: dh->dh_addr += dcount;
! 566: }
! 567: dh->dh_flags |= SBC_DH_DONE;
! 568: }
! 569:
! 570: /*
! 571: * OK. No bus error occurred above. Clear the nofault flag
! 572: * so we no longer short-circuit bus errors.
! 573: */
! 574: nofault = (int *) 0;
! 575:
! 576: #ifdef SBC_DEBUG
! 577: if (sbc_debug & (SBC_DB_REG | SBC_DB_INTR))
! 578: printf("%s: drq intr complete: csr=0x%x, bus_csr=0x%x\n",
! 579: ncr_sc->sc_dev.dv_xname, *ncr_sc->sci_csr,
! 580: *ncr_sc->sci_bus_csr);
! 581: #endif
! 582:
! 583: return (1);
! 584: }
! 585:
! 586: void
! 587: sbc_dma_alloc(ncr_sc)
! 588: struct ncr5380_softc *ncr_sc;
! 589: {
! 590: struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 591: struct sci_req *sr = ncr_sc->sc_current;
! 592: struct scsi_xfer *xs = sr->sr_xs;
! 593: struct sbc_pdma_handle *dh;
! 594: int i, xlen;
! 595:
! 596: #ifdef DIAGNOSTIC
! 597: if (sr->sr_dma_hand != NULL)
! 598: panic("sbc_dma_alloc: already have PDMA handle");
! 599: #endif
! 600:
! 601: /* Polled transfers shouldn't allocate a PDMA handle. */
! 602: if (sr->sr_flags & SR_IMMED)
! 603: return;
! 604:
! 605: xlen = ncr_sc->sc_datalen;
! 606:
! 607: /* Make sure our caller checked sc_min_dma_len. */
! 608: if (xlen < MIN_DMA_LEN)
! 609: panic("sbc_dma_alloc: len=0x%x", xlen);
! 610:
! 611: /*
! 612: * Find free PDMA handle. Guaranteed to find one since we
! 613: * have as many PDMA handles as the driver has processes.
! 614: * (instances?)
! 615: */
! 616: for (i = 0; i < SCI_OPENINGS; i++) {
! 617: if ((sc->sc_pdma[i].dh_flags & SBC_DH_BUSY) == 0)
! 618: goto found;
! 619: }
! 620: panic("sbc: no free PDMA handles");
! 621: found:
! 622: dh = &sc->sc_pdma[i];
! 623: dh->dh_flags = SBC_DH_BUSY;
! 624: dh->dh_addr = ncr_sc->sc_dataptr;
! 625: dh->dh_len = xlen;
! 626:
! 627: /* Copy the 'write' flag for convenience. */
! 628: if (xs->flags & SCSI_DATA_OUT)
! 629: dh->dh_flags |= SBC_DH_OUT;
! 630:
! 631: sr->sr_dma_hand = dh;
! 632: }
! 633:
! 634: void
! 635: sbc_dma_free(ncr_sc)
! 636: struct ncr5380_softc *ncr_sc;
! 637: {
! 638: struct sci_req *sr = ncr_sc->sc_current;
! 639: struct sbc_pdma_handle *dh = sr->sr_dma_hand;
! 640:
! 641: #ifdef DIAGNOSTIC
! 642: if (sr->sr_dma_hand == NULL)
! 643: panic("sbc_dma_free: no DMA handle");
! 644: #endif
! 645:
! 646: if (ncr_sc->sc_state & NCR_DOINGDMA)
! 647: panic("sbc_dma_free: free while in progress");
! 648:
! 649: if (dh->dh_flags & SBC_DH_BUSY) {
! 650: dh->dh_flags = 0;
! 651: dh->dh_addr = NULL;
! 652: dh->dh_len = 0;
! 653: }
! 654: sr->sr_dma_hand = NULL;
! 655: }
! 656:
! 657: void
! 658: sbc_dma_poll(ncr_sc)
! 659: struct ncr5380_softc *ncr_sc;
! 660: {
! 661: struct sci_req *sr = ncr_sc->sc_current;
! 662:
! 663: /*
! 664: * We shouldn't arrive here; if SR_IMMED is set, then
! 665: * dma_alloc() should have refused to allocate a handle
! 666: * for the transfer. This forces the polled PDMA code
! 667: * to handle the request...
! 668: */
! 669: #ifdef SBC_DEBUG
! 670: if (sbc_debug & SBC_DB_DMA)
! 671: printf("%s: lost DRQ interrupt?\n", ncr_sc->sc_dev.dv_xname);
! 672: #endif
! 673: sr->sr_flags |= SR_OVERDUE;
! 674: }
! 675:
! 676: void
! 677: sbc_dma_setup(ncr_sc)
! 678: struct ncr5380_softc *ncr_sc;
! 679: {
! 680: /* Not needed; we don't have real DMA */
! 681: }
! 682:
! 683: void
! 684: sbc_dma_start(ncr_sc)
! 685: struct ncr5380_softc *ncr_sc;
! 686: {
! 687: struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 688: struct sci_req *sr = ncr_sc->sc_current;
! 689: struct sbc_pdma_handle *dh = sr->sr_dma_hand;
! 690:
! 691: /*
! 692: * Match bus phase, clear pending interrupts, set DMA mode, and
! 693: * assert data bus (for writing only), then start the transfer.
! 694: */
! 695: if (dh->dh_flags & SBC_DH_OUT) {
! 696: *ncr_sc->sci_tcmd = PHASE_DATA_OUT;
! 697: SCI_CLR_INTR(ncr_sc);
! 698: if (sc->sc_clrintr)
! 699: (*sc->sc_clrintr)(ncr_sc);
! 700: *ncr_sc->sci_mode |= SCI_MODE_DMA;
! 701: *ncr_sc->sci_icmd = SCI_ICMD_DATA;
! 702: *ncr_sc->sci_dma_send = 0;
! 703: } else {
! 704: *ncr_sc->sci_tcmd = PHASE_DATA_IN;
! 705: SCI_CLR_INTR(ncr_sc);
! 706: if (sc->sc_clrintr)
! 707: (*sc->sc_clrintr)(ncr_sc);
! 708: *ncr_sc->sci_mode |= SCI_MODE_DMA;
! 709: *ncr_sc->sci_icmd = 0;
! 710: *ncr_sc->sci_irecv = 0;
! 711: }
! 712: ncr_sc->sc_state |= NCR_DOINGDMA;
! 713:
! 714: #ifdef SBC_DEBUG
! 715: if (sbc_debug & SBC_DB_DMA)
! 716: printf("%s: PDMA started, va=%p, len=0x%x\n",
! 717: ncr_sc->sc_dev.dv_xname, dh->dh_addr, dh->dh_len);
! 718: #endif
! 719: }
! 720:
! 721: void
! 722: sbc_dma_stop(ncr_sc)
! 723: struct ncr5380_softc *ncr_sc;
! 724: {
! 725: struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 726: struct sci_req *sr = ncr_sc->sc_current;
! 727: struct sbc_pdma_handle *dh = sr->sr_dma_hand;
! 728: int ntrans;
! 729:
! 730: if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) {
! 731: #ifdef SBC_DEBUG
! 732: if (sbc_debug & SBC_DB_DMA)
! 733: printf("%s: dma_stop: DMA not running\n",
! 734: ncr_sc->sc_dev.dv_xname);
! 735: #endif
! 736: return;
! 737: }
! 738: ncr_sc->sc_state &= ~NCR_DOINGDMA;
! 739:
! 740: if ((ncr_sc->sc_state & NCR_ABORTING) == 0) {
! 741: ntrans = ncr_sc->sc_datalen - dh->dh_len;
! 742:
! 743: #ifdef SBC_DEBUG
! 744: if (sbc_debug & SBC_DB_DMA)
! 745: printf("%s: dma_stop: ntrans=0x%x\n",
! 746: ncr_sc->sc_dev.dv_xname, ntrans);
! 747: #endif
! 748:
! 749: if (ntrans > ncr_sc->sc_datalen)
! 750: panic("sbc_dma_stop: excess transfer");
! 751:
! 752: /* Adjust data pointer */
! 753: ncr_sc->sc_dataptr += ntrans;
! 754: ncr_sc->sc_datalen -= ntrans;
! 755:
! 756: /* Clear any pending interrupts. */
! 757: SCI_CLR_INTR(ncr_sc);
! 758: if (sc->sc_clrintr)
! 759: (*sc->sc_clrintr)(ncr_sc);
! 760: }
! 761:
! 762: /* Put SBIC back into PIO mode. */
! 763: *ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 764: *ncr_sc->sci_icmd = 0;
! 765:
! 766: #ifdef SBC_DEBUG
! 767: if (sbc_debug & SBC_DB_REG)
! 768: printf("%s: dma_stop: csr=0x%x, bus_csr=0x%x\n",
! 769: ncr_sc->sc_dev.dv_xname, *ncr_sc->sci_csr,
! 770: *ncr_sc->sci_bus_csr);
! 771: #endif
! 772: }
CVSweb