19885cf45Sralph /*-
223b2dbcbSbostic * Copyright (c) 1992, 1993
323b2dbcbSbostic * The Regents of the University of California. All rights reserved.
46c50d0f2Smckusick *
56c50d0f2Smckusick * This code is derived from software contributed to Berkeley by
69885cf45Sralph * Ralph Campbell and Rick Macklem.
76c50d0f2Smckusick *
86c50d0f2Smckusick * %sccs.include.redist.c%
96c50d0f2Smckusick *
10*de6ace06Smckusick * @(#)sii.c 8.4 (Berkeley) 11/30/94
116c50d0f2Smckusick *
126c50d0f2Smckusick * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c,
1302f3033eSralph * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)";
146c50d0f2Smckusick */
156c50d0f2Smckusick
166c50d0f2Smckusick #include "sii.h"
176c50d0f2Smckusick #if NSII > 0
186c50d0f2Smckusick /*
196c50d0f2Smckusick * SCSI interface driver
206c50d0f2Smckusick */
21864bf03fSbostic #include <sys/param.h>
22864bf03fSbostic #include <sys/systm.h>
23864bf03fSbostic #include <sys/dkstat.h>
24864bf03fSbostic #include <sys/buf.h>
25864bf03fSbostic #include <sys/conf.h>
26864bf03fSbostic #include <sys/errno.h>
276c50d0f2Smckusick
28864bf03fSbostic #include <machine/machConst.h>
296f0e665cSbostic #include <pmax/dev/device.h>
306f0e665cSbostic #include <pmax/dev/scsi.h>
316f0e665cSbostic #include <pmax/dev/siireg.h>
326c50d0f2Smckusick
339885cf45Sralph #include <pmax/pmax/kn01.h>
349885cf45Sralph
356c50d0f2Smckusick int siiprobe();
366c50d0f2Smckusick void siistart();
376c50d0f2Smckusick struct driver siidriver = {
386c50d0f2Smckusick "sii", siiprobe, siistart, 0,
396c50d0f2Smckusick };
406c50d0f2Smckusick
416c50d0f2Smckusick typedef struct scsi_state {
426c50d0f2Smckusick int statusByte; /* status byte returned during STATUS_PHASE */
436c50d0f2Smckusick int dmaDataPhase; /* which data phase to expect */
446c50d0f2Smckusick int dmaCurPhase; /* SCSI phase if DMA is in progress */
456c50d0f2Smckusick int dmaPrevPhase; /* SCSI phase of DMA suspended by disconnect */
466c50d0f2Smckusick u_short *dmaAddr[2]; /* DMA buffer memory address */
476c50d0f2Smckusick int dmaBufIndex; /* which of the above is currently in use */
486c50d0f2Smckusick int dmalen; /* amount to transfer in this chunk */
496c50d0f2Smckusick int cmdlen; /* total remaining amount of cmd to transfer */
506c50d0f2Smckusick u_char *cmd; /* current pointer within scsicmd->cmd */
516c50d0f2Smckusick int buflen; /* total remaining amount of data to transfer */
526c50d0f2Smckusick char *buf; /* current pointer within scsicmd->buf */
536c50d0f2Smckusick u_short flags; /* see below */
546c50d0f2Smckusick u_short prevComm; /* command reg before disconnect */
556c50d0f2Smckusick u_short dmaCtrl; /* DMA control register if disconnect */
566c50d0f2Smckusick u_short dmaAddrL; /* DMA address register if disconnect */
576c50d0f2Smckusick u_short dmaAddrH; /* DMA address register if disconnect */
586c50d0f2Smckusick u_short dmaCnt; /* DMA count if disconnect */
596c50d0f2Smckusick u_short dmaByte; /* DMA byte if disconnect on odd boundary */
606c50d0f2Smckusick u_short dmaReqAck; /* DMA synchronous xfer offset or 0 if async */
616c50d0f2Smckusick } State;
626c50d0f2Smckusick
636c50d0f2Smckusick /* state flags */
646c50d0f2Smckusick #define FIRST_DMA 0x01 /* true if no data DMA started yet */
65f327dcccSmckusick #define PARITY_ERR 0x02 /* true if parity error seen */
666c50d0f2Smckusick
676c50d0f2Smckusick #define SII_NCMD 7
686c50d0f2Smckusick struct siisoftc {
696c50d0f2Smckusick SIIRegs *sc_regs; /* HW address of SII controller chip */
706c50d0f2Smckusick int sc_flags;
716c50d0f2Smckusick int sc_target; /* target SCSI ID if connected */
726c50d0f2Smckusick ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */
736c50d0f2Smckusick State sc_st[SII_NCMD]; /* state info for each active command */
746c50d0f2Smckusick } sii_softc[NSII];
756c50d0f2Smckusick
766c50d0f2Smckusick /*
776c50d0f2Smckusick * MACROS for timing out spin loops.
786c50d0f2Smckusick *
796c50d0f2Smckusick * Wait until expression is true.
806c50d0f2Smckusick *
816c50d0f2Smckusick * Control register bits can change at any time so when the CPU
826c50d0f2Smckusick * reads a register, the bits might change and
836c50d0f2Smckusick * invalidate the setup and hold times for the CPU.
846c50d0f2Smckusick * This macro reads the register twice to be sure the value is stable.
856c50d0f2Smckusick *
866c50d0f2Smckusick * args: var - variable to save control register contents
876c50d0f2Smckusick * reg - control register to read
886c50d0f2Smckusick * expr - expression to spin on
896c50d0f2Smckusick * spincount - maximum number of times through the loop
906c50d0f2Smckusick * cntr - variable for number of tries
916c50d0f2Smckusick */
926c50d0f2Smckusick #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \
93f327dcccSmckusick register u_int tmp = reg; \
946c50d0f2Smckusick for (cntr = 0; cntr < spincount; cntr++) { \
956c50d0f2Smckusick while (tmp != (var = reg)) \
966c50d0f2Smckusick tmp = var; \
976c50d0f2Smckusick if (expr) \
986c50d0f2Smckusick break; \
996c50d0f2Smckusick if (cntr >= 100) \
1006c50d0f2Smckusick DELAY(100); \
1016c50d0f2Smckusick } \
1026c50d0f2Smckusick }
1036c50d0f2Smckusick
1046c50d0f2Smckusick #ifdef DEBUG
1056c50d0f2Smckusick int sii_debug = 1;
1066c50d0f2Smckusick int sii_debug_cmd;
1076c50d0f2Smckusick int sii_debug_bn;
1086c50d0f2Smckusick int sii_debug_sz;
1096c50d0f2Smckusick #define NLOG 16
1106c50d0f2Smckusick struct sii_log {
1116c50d0f2Smckusick u_short cstat;
1126c50d0f2Smckusick u_short dstat;
1136c50d0f2Smckusick u_short comm;
1146c50d0f2Smckusick u_short msg;
115f327dcccSmckusick int rlen;
116f327dcccSmckusick int dlen;
1176c50d0f2Smckusick int target;
1186c50d0f2Smckusick } sii_log[NLOG], *sii_logp = sii_log;
1196c50d0f2Smckusick #endif
1206c50d0f2Smckusick
1216c50d0f2Smckusick u_char sii_buf[256]; /* used for extended messages */
1226c50d0f2Smckusick
1236c50d0f2Smckusick #define NORESET 0
1246c50d0f2Smckusick #define RESET 1
1256c50d0f2Smckusick #define NOWAIT 0
1266c50d0f2Smckusick #define WAIT 1
1276c50d0f2Smckusick
1286c50d0f2Smckusick /* define a safe address in the SCSI buffer for doing status & message DMA */
1299885cf45Sralph #define SII_BUF_ADDR (MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) \
1309885cf45Sralph + SII_MAX_DMA_XFER_LENGTH * 14)
1316c50d0f2Smckusick
1329885cf45Sralph static void sii_Reset();
1339885cf45Sralph static void sii_StartCmd();
1349885cf45Sralph static void sii_CmdDone();
1359885cf45Sralph static void sii_DoIntr();
1369885cf45Sralph static void sii_StateChg();
1379885cf45Sralph static void sii_DoSync();
1389885cf45Sralph static void sii_StartDMA();
1399885cf45Sralph static int sii_GetByte();
1406c50d0f2Smckusick
1416c50d0f2Smckusick /*
1426c50d0f2Smckusick * Test to see if device is present.
1436c50d0f2Smckusick * Return true if found and initialized ok.
1446c50d0f2Smckusick */
siiprobe(cp)1456c50d0f2Smckusick siiprobe(cp)
1466c50d0f2Smckusick register struct pmax_ctlr *cp;
1476c50d0f2Smckusick {
1486c50d0f2Smckusick register struct siisoftc *sc;
1496c50d0f2Smckusick register int i;
1506c50d0f2Smckusick
1516c50d0f2Smckusick if (cp->pmax_unit >= NSII)
1526c50d0f2Smckusick return (0);
1536c50d0f2Smckusick sc = &sii_softc[cp->pmax_unit];
1546c50d0f2Smckusick sc->sc_regs = (SIIRegs *)cp->pmax_addr;
1556c50d0f2Smckusick sc->sc_flags = cp->pmax_flags;
1566c50d0f2Smckusick sc->sc_target = -1; /* no command active */
1576c50d0f2Smckusick /*
1586c50d0f2Smckusick * Give each target its own DMA buffer region.
1596c50d0f2Smckusick * Make it big enough for 2 max transfers so we can ping pong buffers
1606c50d0f2Smckusick * while we copy the data.
1616c50d0f2Smckusick */
1626c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) {
1639885cf45Sralph sc->sc_st[i].dmaAddr[0] = (u_short *)
1649885cf45Sralph MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) +
1656c50d0f2Smckusick 2 * SII_MAX_DMA_XFER_LENGTH * i;
1666c50d0f2Smckusick sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] +
1676c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH;
1686c50d0f2Smckusick }
1696c50d0f2Smckusick
1706c50d0f2Smckusick printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr);
1716c50d0f2Smckusick sii_Reset(sc->sc_regs, RESET);
1726c50d0f2Smckusick return (1);
1736c50d0f2Smckusick }
1746c50d0f2Smckusick
1756c50d0f2Smckusick /*
1766c50d0f2Smckusick * Start activity on a SCSI device.
1776c50d0f2Smckusick * We maintain information on each device separately since devices can
1786c50d0f2Smckusick * connect/disconnect during an operation.
1796c50d0f2Smckusick */
1806c50d0f2Smckusick void
siistart(scsicmd)1816c50d0f2Smckusick siistart(scsicmd)
1826c50d0f2Smckusick register ScsiCmd *scsicmd; /* command to start */
1836c50d0f2Smckusick {
1846c50d0f2Smckusick register struct scsi_device *sdp = scsicmd->sd;
1856c50d0f2Smckusick register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr];
1866c50d0f2Smckusick int s;
1876c50d0f2Smckusick
1886c50d0f2Smckusick s = splbio();
1896c50d0f2Smckusick /*
1906c50d0f2Smckusick * Check if another command is already in progress.
1916c50d0f2Smckusick * We may have to change this if we allow SCSI devices with
1926c50d0f2Smckusick * separate LUNs.
1936c50d0f2Smckusick */
1946c50d0f2Smckusick if (sc->sc_cmd[sdp->sd_drive]) {
1956c50d0f2Smckusick printf("sii%d: device %s busy at start\n", sdp->sd_ctlr,
1966c50d0f2Smckusick sdp->sd_driver->d_name);
1976c50d0f2Smckusick (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
1986c50d0f2Smckusick scsicmd->buflen, 0);
1996c50d0f2Smckusick splx(s);
2006c50d0f2Smckusick }
2016c50d0f2Smckusick sc->sc_cmd[sdp->sd_drive] = scsicmd;
2026c50d0f2Smckusick sii_StartCmd(sc, sdp->sd_drive);
2036c50d0f2Smckusick splx(s);
2046c50d0f2Smckusick }
2056c50d0f2Smckusick
2066c50d0f2Smckusick /*
2076c50d0f2Smckusick * Check to see if any SII chips have pending interrupts
2086c50d0f2Smckusick * and process as appropriate.
2096c50d0f2Smckusick */
2106c50d0f2Smckusick void
siiintr(unit)21183f001d9Sralph siiintr(unit)
21283f001d9Sralph int unit;
2136c50d0f2Smckusick {
21483f001d9Sralph register struct siisoftc *sc = &sii_softc[unit];
215f327dcccSmckusick u_int dstat;
2166c50d0f2Smckusick
2176c50d0f2Smckusick /*
2186c50d0f2Smckusick * Find which controller caused the interrupt.
2196c50d0f2Smckusick */
2206c50d0f2Smckusick dstat = sc->sc_regs->dstat;
22183f001d9Sralph if (dstat & (SII_CI | SII_DI))
2226c50d0f2Smckusick sii_DoIntr(sc, dstat);
2236c50d0f2Smckusick }
2246c50d0f2Smckusick
2256c50d0f2Smckusick /*
2266c50d0f2Smckusick * Reset the SII chip and do a SCSI reset if 'reset' is true.
2276c50d0f2Smckusick * NOTE: if !cold && reset, should probably probe for devices
2286c50d0f2Smckusick * since a SCSI bus reset will set UNIT_ATTENTION.
2296c50d0f2Smckusick */
2306c50d0f2Smckusick static void
sii_Reset(regs,reset)2316c50d0f2Smckusick sii_Reset(regs, reset)
2326c50d0f2Smckusick register SIIRegs *regs;
2336c50d0f2Smckusick int reset; /* TRUE => reset SCSI bus */
2346c50d0f2Smckusick {
2356c50d0f2Smckusick
2366c50d0f2Smckusick #ifdef DEBUG
2376c50d0f2Smckusick if (sii_debug > 1)
2386c50d0f2Smckusick printf("sii: RESET\n");
2396c50d0f2Smckusick #endif
2406c50d0f2Smckusick /*
2416c50d0f2Smckusick * Reset the SII chip.
2426c50d0f2Smckusick */
2436c50d0f2Smckusick regs->comm = SII_CHRESET;
2446c50d0f2Smckusick /*
2456c50d0f2Smckusick * Set arbitrated bus mode.
2466c50d0f2Smckusick */
2476c50d0f2Smckusick regs->csr = SII_HPM;
2486c50d0f2Smckusick /*
2496c50d0f2Smckusick * SII is always ID 7.
2506c50d0f2Smckusick */
2516c50d0f2Smckusick regs->id = SII_ID_IO | 7;
2526c50d0f2Smckusick /*
2536c50d0f2Smckusick * Enable SII to drive the SCSI bus.
2546c50d0f2Smckusick */
2556c50d0f2Smckusick regs->dictrl = SII_PRE;
2566c50d0f2Smckusick regs->dmctrl = 0;
2576c50d0f2Smckusick
2586c50d0f2Smckusick if (reset) {
2596c50d0f2Smckusick register int i;
2606c50d0f2Smckusick
2616c50d0f2Smckusick /*
2626c50d0f2Smckusick * Assert SCSI bus reset for at least 25 Usec to clear the
2636c50d0f2Smckusick * world. SII_DO_RST is self clearing.
2646c50d0f2Smckusick * Delay 250 ms before doing any commands.
2656c50d0f2Smckusick */
2666c50d0f2Smckusick regs->comm = SII_DO_RST;
2676c50d0f2Smckusick MachEmptyWriteBuffer();
2686c50d0f2Smckusick DELAY(250000);
2696c50d0f2Smckusick
2706c50d0f2Smckusick /* rearbitrate synchronous offset */
2716c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++)
2726c50d0f2Smckusick sii_softc[0].sc_st[i].dmaReqAck = 0;
2736c50d0f2Smckusick }
2746c50d0f2Smckusick
2756c50d0f2Smckusick /*
2766c50d0f2Smckusick * Clear any pending interrupts from the reset.
2776c50d0f2Smckusick */
2786c50d0f2Smckusick regs->cstat = regs->cstat;
2796c50d0f2Smckusick regs->dstat = regs->dstat;
2806c50d0f2Smckusick /*
2816c50d0f2Smckusick * Set up SII for arbitrated bus mode, SCSI parity checking,
2826c50d0f2Smckusick * Reselect Enable, and Interrupt Enable.
2836c50d0f2Smckusick */
2846c50d0f2Smckusick regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE;
2856c50d0f2Smckusick MachEmptyWriteBuffer();
2866c50d0f2Smckusick }
2876c50d0f2Smckusick
2886c50d0f2Smckusick /*
2896c50d0f2Smckusick * Start a SCSI command by sending the cmd data
2906c50d0f2Smckusick * to a SCSI controller via the SII.
2916c50d0f2Smckusick * Call the device done proceedure if it can't be started.
2926c50d0f2Smckusick * NOTE: we should be called with interrupts disabled.
2936c50d0f2Smckusick */
2946c50d0f2Smckusick static void
sii_StartCmd(sc,target)2956c50d0f2Smckusick sii_StartCmd(sc, target)
2966c50d0f2Smckusick register struct siisoftc *sc; /* which SII to use */
2976c50d0f2Smckusick register int target; /* which command to start */
2986c50d0f2Smckusick {
2996c50d0f2Smckusick register SIIRegs *regs;
3006c50d0f2Smckusick register ScsiCmd *scsicmd;
3016c50d0f2Smckusick register State *state;
302f327dcccSmckusick register u_int status;
3036c50d0f2Smckusick int error, retval;
3046c50d0f2Smckusick
3056c50d0f2Smckusick /* if another command is currently in progress, just wait */
3066c50d0f2Smckusick if (sc->sc_target >= 0)
3076c50d0f2Smckusick return;
3086c50d0f2Smckusick
3096c50d0f2Smckusick /* initialize state information for this command */
3106c50d0f2Smckusick scsicmd = sc->sc_cmd[target];
3116c50d0f2Smckusick state = &sc->sc_st[target];
3126c50d0f2Smckusick state->flags = FIRST_DMA;
3136c50d0f2Smckusick state->prevComm = 0;
3146c50d0f2Smckusick state->dmalen = 0;
3156c50d0f2Smckusick state->dmaCurPhase = -1;
3166c50d0f2Smckusick state->dmaPrevPhase = -1;
3176c50d0f2Smckusick state->dmaBufIndex = 0;
3186c50d0f2Smckusick state->cmd = scsicmd->cmd;
3196c50d0f2Smckusick state->cmdlen = scsicmd->cmdlen;
3206c50d0f2Smckusick if ((state->buflen = scsicmd->buflen) == 0) {
3216c50d0f2Smckusick state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */
3226c50d0f2Smckusick state->buf = (char *)0;
3236c50d0f2Smckusick } else {
3246c50d0f2Smckusick state->dmaDataPhase =
3256c50d0f2Smckusick (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ?
3266c50d0f2Smckusick SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE;
3276c50d0f2Smckusick state->buf = scsicmd->buf;
3286c50d0f2Smckusick }
3296c50d0f2Smckusick
3306c50d0f2Smckusick #ifdef DEBUG
3316c50d0f2Smckusick if (sii_debug > 1) {
3326c50d0f2Smckusick printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n",
3336c50d0f2Smckusick scsicmd->sd->sd_driver->d_name, target,
3346c50d0f2Smckusick scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen,
3356c50d0f2Smckusick state->dmaDataPhase);
3366c50d0f2Smckusick }
3376c50d0f2Smckusick sii_debug_cmd = scsicmd->cmd[0];
338f327dcccSmckusick if (scsicmd->cmd[0] == SCSI_READ_EXT ||
339f327dcccSmckusick scsicmd->cmd[0] == SCSI_WRITE_EXT) {
3406c50d0f2Smckusick sii_debug_bn = (scsicmd->cmd[2] << 24) |
3416c50d0f2Smckusick (scsicmd->cmd[3] << 16) |
3426c50d0f2Smckusick (scsicmd->cmd[4] << 8) |
3436c50d0f2Smckusick scsicmd->cmd[5];
3446c50d0f2Smckusick sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
345f327dcccSmckusick } else {
346f327dcccSmckusick sii_debug_bn = 0;
347f327dcccSmckusick sii_debug_sz = 0;
3486c50d0f2Smckusick }
3496c50d0f2Smckusick #endif
3506c50d0f2Smckusick
3516c50d0f2Smckusick /* try to select the target */
3526c50d0f2Smckusick regs = sc->sc_regs;
3536c50d0f2Smckusick
3546c50d0f2Smckusick /*
3556c50d0f2Smckusick * Another device may have selected us; in which case,
3566c50d0f2Smckusick * this command will be restarted later.
3576c50d0f2Smckusick */
3586c50d0f2Smckusick if ((status = regs->dstat) & (SII_CI | SII_DI)) {
3596c50d0f2Smckusick sii_DoIntr(sc, status);
3606c50d0f2Smckusick return;
3616c50d0f2Smckusick }
3626c50d0f2Smckusick
3636c50d0f2Smckusick sc->sc_target = target;
364f327dcccSmckusick #if 0
365f327dcccSmckusick /* seem to have problems with synchronous transfers */
3666c50d0f2Smckusick if (scsicmd->flags & SCSICMD_USE_SYNC) {
3676c50d0f2Smckusick printf("sii_StartCmd: doing extended msg\n"); /* XXX */
3686c50d0f2Smckusick /*
3696c50d0f2Smckusick * Setup to send both the identify message and the synchronous
3706c50d0f2Smckusick * data transfer request.
3716c50d0f2Smckusick */
3726c50d0f2Smckusick sii_buf[0] = SCSI_DIS_REC_IDENTIFY;
3736c50d0f2Smckusick sii_buf[1] = SCSI_EXTENDED_MSG;
3746c50d0f2Smckusick sii_buf[2] = 3; /* message length */
3756c50d0f2Smckusick sii_buf[3] = SCSI_SYNCHRONOUS_XFER;
3766c50d0f2Smckusick sii_buf[4] = 0;
3776c50d0f2Smckusick sii_buf[5] = 3; /* maximum SII chip supports */
3786c50d0f2Smckusick
3796c50d0f2Smckusick state->dmaCurPhase = SII_MSG_OUT_PHASE,
3806c50d0f2Smckusick state->dmalen = 6;
3816c50d0f2Smckusick CopyToBuffer((u_short *)sii_buf,
3826c50d0f2Smckusick (volatile u_short *)SII_BUF_ADDR, 6);
3836c50d0f2Smckusick regs->slcsr = target;
384f327dcccSmckusick regs->dmctrl = state->dmaReqAck;
385f327dcccSmckusick regs->dmaddrl = (u_short)(SII_BUF_ADDR >> 1);
386f327dcccSmckusick regs->dmaddrh = (u_short)(SII_BUF_ADDR >> 17) & 03;
3876c50d0f2Smckusick regs->dmlotc = 6;
3886c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN |
3896c50d0f2Smckusick SII_CON | SII_MSG_OUT_PHASE;
390f327dcccSmckusick } else
391f327dcccSmckusick #endif
392f327dcccSmckusick {
3936c50d0f2Smckusick /* do a chained, select with ATN and programmed I/O command */
3946c50d0f2Smckusick regs->data = SCSI_DIS_REC_IDENTIFY;
3956c50d0f2Smckusick regs->slcsr = target;
396f327dcccSmckusick regs->dmctrl = state->dmaReqAck;
3976c50d0f2Smckusick regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON |
3986c50d0f2Smckusick SII_MSG_OUT_PHASE;
3996c50d0f2Smckusick }
4006c50d0f2Smckusick MachEmptyWriteBuffer();
4016c50d0f2Smckusick
4026c50d0f2Smckusick /*
4036c50d0f2Smckusick * Wait for something to happen
4046c50d0f2Smckusick * (should happen soon or we would use interrupts).
4056c50d0f2Smckusick */
4066c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI),
407e9679b18Sralph SII_WAIT_COUNT/4, retval);
4086c50d0f2Smckusick
4096c50d0f2Smckusick /* check to see if we are connected OK */
4106c50d0f2Smckusick if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) ==
4116c50d0f2Smckusick (SII_SCH | SII_CON)) {
4126c50d0f2Smckusick regs->cstat = status;
4136c50d0f2Smckusick MachEmptyWriteBuffer();
4146c50d0f2Smckusick
4156c50d0f2Smckusick #ifdef DEBUG
4166c50d0f2Smckusick sii_logp->target = target;
4176c50d0f2Smckusick sii_logp->cstat = status;
4186c50d0f2Smckusick sii_logp->dstat = 0;
4196c50d0f2Smckusick sii_logp->comm = regs->comm;
4206c50d0f2Smckusick sii_logp->msg = -1;
421f327dcccSmckusick sii_logp->rlen = state->buflen;
422f327dcccSmckusick sii_logp->dlen = state->dmalen;
4236c50d0f2Smckusick if (++sii_logp >= &sii_log[NLOG])
4246c50d0f2Smckusick sii_logp = sii_log;
4256c50d0f2Smckusick #endif
4266c50d0f2Smckusick
4276c50d0f2Smckusick /* wait a short time for command phase */
4286c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS,
4296c50d0f2Smckusick SII_WAIT_COUNT, retval);
4306c50d0f2Smckusick #ifdef DEBUG
4316c50d0f2Smckusick if (sii_debug > 2)
4326c50d0f2Smckusick printf("sii_StartCmd: ds %x cnt %d\n", status, retval);
4336c50d0f2Smckusick #endif
4346c50d0f2Smckusick if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) !=
4356c50d0f2Smckusick (SII_MIS | SII_CMD_PHASE)) {
4366c50d0f2Smckusick printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n",
4376c50d0f2Smckusick regs->cstat, status, retval); /* XXX */
4386c50d0f2Smckusick /* process interrupt or continue until it happens */
4396c50d0f2Smckusick if (status & (SII_CI | SII_DI))
4406c50d0f2Smckusick sii_DoIntr(sc, status);
4416c50d0f2Smckusick return;
4426c50d0f2Smckusick }
4436c50d0f2Smckusick regs->dstat = SII_DNE; /* clear Msg Out DMA done */
4446c50d0f2Smckusick
4456c50d0f2Smckusick /* send command data */
4466c50d0f2Smckusick CopyToBuffer((u_short *)state->cmd,
4476c50d0f2Smckusick (volatile u_short *)state->dmaAddr[0], state->cmdlen);
4486c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE,
4496c50d0f2Smckusick state->dmaAddr[0], state->dmalen = scsicmd->cmdlen);
4506c50d0f2Smckusick
4516c50d0f2Smckusick /* wait a little while for DMA to finish */
4526c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI),
4536c50d0f2Smckusick SII_WAIT_COUNT, retval);
4546c50d0f2Smckusick #ifdef DEBUG
4556c50d0f2Smckusick if (sii_debug > 2)
4566c50d0f2Smckusick printf("sii_StartCmd: ds %x, cnt %d\n", status, retval);
4576c50d0f2Smckusick #endif
4586c50d0f2Smckusick if (status & (SII_CI | SII_DI))
4596c50d0f2Smckusick sii_DoIntr(sc, status);
4606c50d0f2Smckusick #ifdef DEBUG
4616c50d0f2Smckusick if (sii_debug > 2)
4626c50d0f2Smckusick printf("sii_StartCmd: DONE ds %x\n", regs->dstat);
4636c50d0f2Smckusick #endif
4646c50d0f2Smckusick return;
4656c50d0f2Smckusick }
4666c50d0f2Smckusick
4676c50d0f2Smckusick /*
4686c50d0f2Smckusick * Another device may have selected us; in which case,
4696c50d0f2Smckusick * this command will be restarted later.
4706c50d0f2Smckusick */
4716c50d0f2Smckusick if (status & (SII_CI | SII_DI)) {
4726c50d0f2Smckusick sii_DoIntr(sc, regs->dstat);
4736c50d0f2Smckusick return;
4746c50d0f2Smckusick }
4756c50d0f2Smckusick
4766c50d0f2Smckusick /*
4776c50d0f2Smckusick * Disconnect if selection command still in progress.
4786c50d0f2Smckusick */
4796c50d0f2Smckusick if (status & SII_SIP) {
4806c50d0f2Smckusick error = ENXIO; /* device didn't respond */
4816c50d0f2Smckusick regs->comm = SII_DISCON;
4826c50d0f2Smckusick MachEmptyWriteBuffer();
4836c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->cstat,
4846c50d0f2Smckusick !(status & (SII_CON | SII_SIP)),
4856c50d0f2Smckusick SII_WAIT_COUNT, retval);
4866c50d0f2Smckusick } else
4876c50d0f2Smckusick error = EBUSY; /* couldn't get the bus */
4886c50d0f2Smckusick #ifdef DEBUG
489e9679b18Sralph if (sii_debug > 1)
4906c50d0f2Smckusick printf("sii_StartCmd: Couldn't select target %d error %d\n",
4916c50d0f2Smckusick target, error);
4926c50d0f2Smckusick #endif
4936c50d0f2Smckusick sc->sc_target = -1;
4946c50d0f2Smckusick regs->cstat = 0xffff;
4956c50d0f2Smckusick regs->dstat = 0xffff;
4966c50d0f2Smckusick regs->comm = 0;
4976c50d0f2Smckusick MachEmptyWriteBuffer();
4986c50d0f2Smckusick sii_CmdDone(sc, target, error);
4996c50d0f2Smckusick }
5006c50d0f2Smckusick
5016c50d0f2Smckusick /*
5026c50d0f2Smckusick * Process interrupt conditions.
5036c50d0f2Smckusick */
5046c50d0f2Smckusick static void
sii_DoIntr(sc,dstat)5056c50d0f2Smckusick sii_DoIntr(sc, dstat)
5066c50d0f2Smckusick register struct siisoftc *sc;
507f327dcccSmckusick register u_int dstat;
5086c50d0f2Smckusick {
5096c50d0f2Smckusick register SIIRegs *regs = sc->sc_regs;
5106c50d0f2Smckusick register State *state;
511f327dcccSmckusick register u_int cstat;
512f327dcccSmckusick int i, msg;
513f327dcccSmckusick u_int comm;
5146c50d0f2Smckusick
5156c50d0f2Smckusick again:
5166c50d0f2Smckusick comm = regs->comm;
5176c50d0f2Smckusick
5186c50d0f2Smckusick #ifdef DEBUG
5196c50d0f2Smckusick if (sii_debug > 3)
5206c50d0f2Smckusick printf("sii_DoIntr: cs %x, ds %x cm %x ",
5216c50d0f2Smckusick regs->cstat, dstat, comm);
5226c50d0f2Smckusick sii_logp->target = sc->sc_target;
5236c50d0f2Smckusick sii_logp->cstat = regs->cstat;
5246c50d0f2Smckusick sii_logp->dstat = dstat;
5256c50d0f2Smckusick sii_logp->comm = comm;
5266c50d0f2Smckusick sii_logp->msg = -1;
527f327dcccSmckusick if (sc->sc_target >= 0) {
528f327dcccSmckusick sii_logp->rlen = sc->sc_st[sc->sc_target].buflen;
529f327dcccSmckusick sii_logp->dlen = sc->sc_st[sc->sc_target].dmalen;
530f327dcccSmckusick } else {
531f327dcccSmckusick sii_logp->rlen = 0;
532f327dcccSmckusick sii_logp->dlen = 0;
533f327dcccSmckusick }
5346c50d0f2Smckusick if (++sii_logp >= &sii_log[NLOG])
5356c50d0f2Smckusick sii_logp = sii_log;
5366c50d0f2Smckusick #endif
5376c50d0f2Smckusick
5386c50d0f2Smckusick regs->dstat = dstat; /* acknowledge everything */
5396c50d0f2Smckusick MachEmptyWriteBuffer();
5406c50d0f2Smckusick
5416c50d0f2Smckusick if (dstat & SII_CI) {
5426c50d0f2Smckusick /* deglitch cstat register */
5436c50d0f2Smckusick msg = regs->cstat;
5446c50d0f2Smckusick while (msg != (cstat = regs->cstat))
5456c50d0f2Smckusick msg = cstat;
5466c50d0f2Smckusick regs->cstat = cstat; /* acknowledge everything */
5476c50d0f2Smckusick MachEmptyWriteBuffer();
5486c50d0f2Smckusick #ifdef DEBUG
5496c50d0f2Smckusick if (sii_logp > sii_log)
5506c50d0f2Smckusick sii_logp[-1].cstat = cstat;
5516c50d0f2Smckusick else
5526c50d0f2Smckusick sii_log[NLOG - 1].cstat = cstat;
5536c50d0f2Smckusick #endif
5546c50d0f2Smckusick
5556c50d0f2Smckusick /* check for a BUS RESET */
5566c50d0f2Smckusick if (cstat & SII_RST) {
5576c50d0f2Smckusick printf("sii%d: SCSI bus reset!!\n", sc - sii_softc);
5586c50d0f2Smckusick /* need to flush disconnected commands */
55983f001d9Sralph for (i = 0; i < SII_NCMD; i++) {
56083f001d9Sralph if (!sc->sc_cmd[i])
56183f001d9Sralph continue;
5626c50d0f2Smckusick sii_CmdDone(sc, i, EIO);
56383f001d9Sralph }
5646c50d0f2Smckusick /* rearbitrate synchronous offset */
5656c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++)
5666c50d0f2Smckusick sc->sc_st[i].dmaReqAck = 0;
5676c50d0f2Smckusick sc->sc_target = -1;
5686c50d0f2Smckusick return;
5696c50d0f2Smckusick }
5706c50d0f2Smckusick
5716c50d0f2Smckusick #ifdef notdef
5726c50d0f2Smckusick /*
5736c50d0f2Smckusick * Check for a BUS ERROR.
5746c50d0f2Smckusick * According to DEC, this feature doesn't really work
5756c50d0f2Smckusick * and to just clear the bit if it's set.
5766c50d0f2Smckusick */
5776c50d0f2Smckusick if (cstat & SII_BER) {
5786c50d0f2Smckusick }
5796c50d0f2Smckusick #endif
5806c50d0f2Smckusick
5816c50d0f2Smckusick /* check for state change */
5826c50d0f2Smckusick if (cstat & SII_SCH) {
5836c50d0f2Smckusick sii_StateChg(sc, cstat);
5846c50d0f2Smckusick comm = regs->comm;
5856c50d0f2Smckusick }
5866c50d0f2Smckusick }
5876c50d0f2Smckusick
5886c50d0f2Smckusick /* check for DMA completion */
5896c50d0f2Smckusick if (dstat & SII_DNE) {
5906c50d0f2Smckusick u_short *dma;
5916c50d0f2Smckusick char *buf;
5926c50d0f2Smckusick
5936c50d0f2Smckusick /*
5946c50d0f2Smckusick * There is a race condition with SII_SCH. There is a short
5956c50d0f2Smckusick * window between the time a SII_SCH is seen after a disconnect
5966c50d0f2Smckusick * and when the SII_SCH is cleared. A reselect can happen
5976c50d0f2Smckusick * in this window and we will clear the SII_SCH without
5986c50d0f2Smckusick * processing the reconnect.
5996c50d0f2Smckusick */
6006c50d0f2Smckusick if (sc->sc_target < 0) {
6016c50d0f2Smckusick cstat = regs->cstat;
6026c50d0f2Smckusick printf("sii%d: target %d DNE?? dev %d,%d cs %x\n",
6036c50d0f2Smckusick sc - sii_softc, sc->sc_target,
6046c50d0f2Smckusick regs->slcsr, regs->destat,
6056c50d0f2Smckusick cstat); /* XXX */
6066c50d0f2Smckusick if (cstat & SII_DST) {
6076c50d0f2Smckusick sc->sc_target = regs->destat;
6086c50d0f2Smckusick state->prevComm = 0;
6096c50d0f2Smckusick } else
6106c50d0f2Smckusick panic("sc_target 1");
6116c50d0f2Smckusick }
6126c50d0f2Smckusick state = &sc->sc_st[sc->sc_target];
613f327dcccSmckusick /* check for a PARITY ERROR */
614f327dcccSmckusick if (dstat & SII_IPE) {
615f327dcccSmckusick state->flags |= PARITY_ERR;
616f327dcccSmckusick printf("sii%d: Parity error!!\n", sc - sii_softc);
617f327dcccSmckusick goto abort;
618f327dcccSmckusick }
6196c50d0f2Smckusick /* dmalen = amount left to transfer, i = amount transfered */
6206c50d0f2Smckusick i = state->dmalen;
6216c50d0f2Smckusick state->dmalen = 0;
6226c50d0f2Smckusick state->dmaCurPhase = -1;
6236c50d0f2Smckusick #ifdef DEBUG
6246c50d0f2Smckusick if (sii_debug > 4) {
6256c50d0f2Smckusick printf("DNE: amt %d ", i);
6266c50d0f2Smckusick if (!(dstat & SII_TCZ))
6276c50d0f2Smckusick printf("no TCZ?? (%d) ", regs->dmlotc);
6286c50d0f2Smckusick } else if (!(dstat & SII_TCZ)) {
6296c50d0f2Smckusick printf("sii%d: device %d: no TCZ?? (%d)\n",
6306c50d0f2Smckusick sc - sii_softc, sc->sc_target, regs->dmlotc);
6316c50d0f2Smckusick sii_DumpLog(); /* XXX */
6326c50d0f2Smckusick }
6336c50d0f2Smckusick #endif
6346c50d0f2Smckusick switch (comm & SII_PHASE_MSK) {
6356c50d0f2Smckusick case SII_CMD_PHASE:
6366c50d0f2Smckusick state->cmdlen -= i;
6376c50d0f2Smckusick break;
6386c50d0f2Smckusick
6396c50d0f2Smckusick case SII_DATA_IN_PHASE:
6406c50d0f2Smckusick /* check for more data for the same phase */
6416c50d0f2Smckusick dma = state->dmaAddr[state->dmaBufIndex];
6426c50d0f2Smckusick buf = state->buf;
6436c50d0f2Smckusick state->buf += i;
6446c50d0f2Smckusick state->buflen -= i;
6456c50d0f2Smckusick if (state->buflen > 0 && !(dstat & SII_MIS)) {
6466c50d0f2Smckusick int len;
6476c50d0f2Smckusick
6486c50d0f2Smckusick /* start reading next chunk */
6496c50d0f2Smckusick len = state->buflen;
6506c50d0f2Smckusick if (len > SII_MAX_DMA_XFER_LENGTH)
6516c50d0f2Smckusick len = SII_MAX_DMA_XFER_LENGTH;
6526c50d0f2Smckusick state->dmaBufIndex = !state->dmaBufIndex;
6536c50d0f2Smckusick sii_StartDMA(regs,
6546c50d0f2Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE,
6556c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
6566c50d0f2Smckusick state->dmalen = len);
6576c50d0f2Smckusick dstat &= ~(SII_IBF | SII_TBE);
6586c50d0f2Smckusick }
6596c50d0f2Smckusick /* copy in the data */
6606c50d0f2Smckusick CopyFromBuffer((volatile u_short *)dma, buf, i);
6616c50d0f2Smckusick break;
6626c50d0f2Smckusick
6636c50d0f2Smckusick case SII_DATA_OUT_PHASE:
6646c50d0f2Smckusick state->dmaBufIndex = !state->dmaBufIndex;
6656c50d0f2Smckusick state->buf += i;
6666c50d0f2Smckusick state->buflen -= i;
6676c50d0f2Smckusick
6686c50d0f2Smckusick /* check for more data for the same phase */
6696c50d0f2Smckusick if (state->buflen <= 0 || (dstat & SII_MIS))
6706c50d0f2Smckusick break;
6716c50d0f2Smckusick
6726c50d0f2Smckusick /* start next chunk */
6736c50d0f2Smckusick i = state->buflen;
6746c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) {
6756c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase =
6766c50d0f2Smckusick SII_DATA_OUT_PHASE,
6776c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
6786c50d0f2Smckusick state->dmalen =
6796c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH);
6806c50d0f2Smckusick /* prepare for next chunk */
6816c50d0f2Smckusick i -= SII_MAX_DMA_XFER_LENGTH;
6826c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH)
6836c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH;
6846c50d0f2Smckusick CopyToBuffer((u_short *)(state->buf +
6856c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH),
6866c50d0f2Smckusick (volatile u_short *)
6876c50d0f2Smckusick state->dmaAddr[!state->dmaBufIndex], i);
6886c50d0f2Smckusick } else {
6896c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase =
6906c50d0f2Smckusick SII_DATA_OUT_PHASE,
6916c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
6926c50d0f2Smckusick state->dmalen = i);
6936c50d0f2Smckusick }
6946c50d0f2Smckusick dstat &= ~(SII_IBF | SII_TBE);
6956c50d0f2Smckusick }
6966c50d0f2Smckusick }
6976c50d0f2Smckusick
6986c50d0f2Smckusick /* check for phase change or another MsgIn/Out */
6996c50d0f2Smckusick if (dstat & (SII_MIS | SII_IBF | SII_TBE)) {
7006c50d0f2Smckusick /*
7016c50d0f2Smckusick * There is a race condition with SII_SCH. There is a short
7026c50d0f2Smckusick * window between the time a SII_SCH is seen after a disconnect
7036c50d0f2Smckusick * and when the SII_SCH is cleared. A reselect can happen
7046c50d0f2Smckusick * in this window and we will clear the SII_SCH without
7056c50d0f2Smckusick * processing the reconnect.
7066c50d0f2Smckusick */
7076c50d0f2Smckusick if (sc->sc_target < 0) {
7086c50d0f2Smckusick cstat = regs->cstat;
7096c50d0f2Smckusick printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n",
7106c50d0f2Smckusick sc - sii_softc, sc->sc_target,
7116c50d0f2Smckusick regs->slcsr, regs->destat,
7126c50d0f2Smckusick cstat, dstat); /* XXX */
7136c50d0f2Smckusick if (cstat & SII_DST) {
7146c50d0f2Smckusick sc->sc_target = regs->destat;
7156c50d0f2Smckusick state->prevComm = 0;
716f327dcccSmckusick } else {
717*de6ace06Smckusick #ifdef DEBUG
718f327dcccSmckusick sii_DumpLog();
719*de6ace06Smckusick #endif
7206c50d0f2Smckusick panic("sc_target 2");
7216c50d0f2Smckusick }
722f327dcccSmckusick }
7236c50d0f2Smckusick state = &sc->sc_st[sc->sc_target];
7246c50d0f2Smckusick switch (dstat & SII_PHASE_MSK) {
7256c50d0f2Smckusick case SII_CMD_PHASE:
7266c50d0f2Smckusick if (state->dmaPrevPhase >= 0) {
7276c50d0f2Smckusick /* restart DMA after disconnect/reconnect */
7286c50d0f2Smckusick if (state->dmaPrevPhase != SII_CMD_PHASE) {
7296c50d0f2Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n",
7306c50d0f2Smckusick sc - sii_softc, sc->sc_target);
7316c50d0f2Smckusick goto abort;
7326c50d0f2Smckusick }
7336c50d0f2Smckusick state->dmaCurPhase = SII_CMD_PHASE;
7346c50d0f2Smckusick state->dmaPrevPhase = -1;
7356c50d0f2Smckusick regs->dmaddrl = state->dmaAddrL;
7366c50d0f2Smckusick regs->dmaddrh = state->dmaAddrH;
7376c50d0f2Smckusick regs->dmlotc = state->dmaCnt;
7386c50d0f2Smckusick if (state->dmaCnt & 1)
7396c50d0f2Smckusick regs->dmabyte = state->dmaByte;
7406c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER |
7416c50d0f2Smckusick (comm & SII_STATE_MSK) | SII_CMD_PHASE;
7426c50d0f2Smckusick MachEmptyWriteBuffer();
7436c50d0f2Smckusick #ifdef DEBUG
7446c50d0f2Smckusick if (sii_debug > 4)
7456c50d0f2Smckusick printf("Cmd dcnt %d dadr %x ",
7466c50d0f2Smckusick state->dmaCnt,
7476c50d0f2Smckusick (state->dmaAddrH << 16) |
7486c50d0f2Smckusick state->dmaAddrL);
7496c50d0f2Smckusick #endif
7506c50d0f2Smckusick } else {
7516c50d0f2Smckusick /* send command data */
7526c50d0f2Smckusick i = state->cmdlen;
7536c50d0f2Smckusick if (i == 0) {
7546c50d0f2Smckusick printf("sii%d: device %d: cmd count exceeded\n",
7556c50d0f2Smckusick sc - sii_softc, sc->sc_target);
7566c50d0f2Smckusick goto abort;
7576c50d0f2Smckusick }
7586c50d0f2Smckusick CopyToBuffer((u_short *)state->cmd,
7596c50d0f2Smckusick (volatile u_short *)state->dmaAddr[0],
7606c50d0f2Smckusick i);
7616c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase =
7626c50d0f2Smckusick SII_CMD_PHASE, state->dmaAddr[0],
7636c50d0f2Smckusick state->dmalen = i);
7646c50d0f2Smckusick }
7656c50d0f2Smckusick /* wait a short time for XFER complete */
7666c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
7676c50d0f2Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
7686c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) {
7696c50d0f2Smckusick #ifdef DEBUG
7706c50d0f2Smckusick if (sii_debug > 4)
7716c50d0f2Smckusick printf("cnt %d\n", i);
7726c50d0f2Smckusick else if (sii_debug > 0)
7736c50d0f2Smckusick printf("sii_DoIntr: cmd wait ds %x cnt %d\n",
7746c50d0f2Smckusick dstat, i);
7756c50d0f2Smckusick #endif
7766c50d0f2Smckusick goto again;
7776c50d0f2Smckusick }
7786c50d0f2Smckusick break;
7796c50d0f2Smckusick
7806c50d0f2Smckusick case SII_DATA_IN_PHASE:
7816c50d0f2Smckusick case SII_DATA_OUT_PHASE:
7826c50d0f2Smckusick if (state->cmdlen > 0) {
7836c50d0f2Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n",
7846c50d0f2Smckusick sc - sii_softc, sc->sc_target,
7856c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0],
7866c50d0f2Smckusick state->cmdlen);
7876c50d0f2Smckusick state->cmdlen = 0;
7886c50d0f2Smckusick #ifdef DEBUG
7896c50d0f2Smckusick sii_DumpLog();
7906c50d0f2Smckusick #endif
7916c50d0f2Smckusick }
7926c50d0f2Smckusick if (state->dmaPrevPhase >= 0) {
7936c50d0f2Smckusick /* restart DMA after disconnect/reconnect */
7946c50d0f2Smckusick if (state->dmaPrevPhase !=
7956c50d0f2Smckusick (dstat & SII_PHASE_MSK)) {
7966c50d0f2Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n",
7976c50d0f2Smckusick sc - sii_softc, sc->sc_target);
7986c50d0f2Smckusick goto abort;
7996c50d0f2Smckusick }
8006c50d0f2Smckusick state->dmaCurPhase = state->dmaPrevPhase;
8016c50d0f2Smckusick state->dmaPrevPhase = -1;
8026c50d0f2Smckusick regs->dmaddrl = state->dmaAddrL;
8036c50d0f2Smckusick regs->dmaddrh = state->dmaAddrH;
8046c50d0f2Smckusick regs->dmlotc = state->dmaCnt;
8056c50d0f2Smckusick if (state->dmaCnt & 1)
8066c50d0f2Smckusick regs->dmabyte = state->dmaByte;
8076c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER |
8086c50d0f2Smckusick (comm & SII_STATE_MSK) |
8096c50d0f2Smckusick state->dmaCurPhase;
8106c50d0f2Smckusick MachEmptyWriteBuffer();
8116c50d0f2Smckusick #ifdef DEBUG
8126c50d0f2Smckusick if (sii_debug > 4)
8136c50d0f2Smckusick printf("Data %d dcnt %d dadr %x ",
8146c50d0f2Smckusick state->dmaDataPhase,
8156c50d0f2Smckusick state->dmaCnt,
8166c50d0f2Smckusick (state->dmaAddrH << 16) |
8176c50d0f2Smckusick state->dmaAddrL);
8186c50d0f2Smckusick #endif
8196c50d0f2Smckusick break;
8206c50d0f2Smckusick }
8216c50d0f2Smckusick if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) {
8226c50d0f2Smckusick printf("sii%d: device %d: cmd %x: dma phase doesn't match\n",
8236c50d0f2Smckusick sc - sii_softc, sc->sc_target,
8246c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0]);
8256c50d0f2Smckusick goto abort;
8266c50d0f2Smckusick }
8276c50d0f2Smckusick #ifdef DEBUG
8286c50d0f2Smckusick if (sii_debug > 4) {
8296c50d0f2Smckusick printf("Data %d ", state->dmaDataPhase);
8306c50d0f2Smckusick if (sii_debug > 5)
8316c50d0f2Smckusick printf("\n");
8326c50d0f2Smckusick }
8336c50d0f2Smckusick #endif
8346c50d0f2Smckusick i = state->buflen;
8356c50d0f2Smckusick if (i == 0) {
8366c50d0f2Smckusick printf("sii%d: device %d: data count exceeded\n",
8376c50d0f2Smckusick sc - sii_softc, sc->sc_target);
8386c50d0f2Smckusick goto abort;
8396c50d0f2Smckusick }
8406c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH)
8416c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH;
8426c50d0f2Smckusick if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) {
8436c50d0f2Smckusick sii_StartDMA(regs,
8446c50d0f2Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE,
8456c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
8466c50d0f2Smckusick state->dmalen = i);
8476c50d0f2Smckusick break;
8486c50d0f2Smckusick }
8496c50d0f2Smckusick /* start first chunk */
8506c50d0f2Smckusick if (state->flags & FIRST_DMA) {
8516c50d0f2Smckusick state->flags &= ~FIRST_DMA;
8526c50d0f2Smckusick CopyToBuffer((u_short *)state->buf,
8536c50d0f2Smckusick (volatile u_short *)
8546c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], i);
8556c50d0f2Smckusick }
8566c50d0f2Smckusick sii_StartDMA(regs,
8576c50d0f2Smckusick state->dmaCurPhase = SII_DATA_OUT_PHASE,
8586c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
8596c50d0f2Smckusick state->dmalen = i);
8606c50d0f2Smckusick i = state->buflen - SII_MAX_DMA_XFER_LENGTH;
8616c50d0f2Smckusick if (i > 0) {
8626c50d0f2Smckusick /* prepare for next chunk */
8636c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH)
8646c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH;
8656c50d0f2Smckusick CopyToBuffer((u_short *)(state->buf +
8666c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH),
8676c50d0f2Smckusick (volatile u_short *)
8686c50d0f2Smckusick state->dmaAddr[!state->dmaBufIndex], i);
8696c50d0f2Smckusick }
8706c50d0f2Smckusick break;
8716c50d0f2Smckusick
8726c50d0f2Smckusick case SII_STATUS_PHASE:
8736c50d0f2Smckusick if (state->cmdlen > 0) {
8746c50d0f2Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n",
8756c50d0f2Smckusick sc - sii_softc, sc->sc_target,
8766c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0],
8776c50d0f2Smckusick state->cmdlen);
8786c50d0f2Smckusick state->cmdlen = 0;
8796c50d0f2Smckusick #ifdef DEBUG
8806c50d0f2Smckusick sii_DumpLog();
8816c50d0f2Smckusick #endif
8826c50d0f2Smckusick }
8836c50d0f2Smckusick
8846c50d0f2Smckusick /* read amount transfered if DMA didn't finish */
8856c50d0f2Smckusick if (state->dmalen > 0) {
8866c50d0f2Smckusick i = state->dmalen - regs->dmlotc;
8876c50d0f2Smckusick state->dmalen = 0;
8886c50d0f2Smckusick state->dmaCurPhase = -1;
8896c50d0f2Smckusick regs->dmlotc = 0;
8906c50d0f2Smckusick regs->comm = comm &
8916c50d0f2Smckusick (SII_STATE_MSK | SII_PHASE_MSK);
8926c50d0f2Smckusick MachEmptyWriteBuffer();
8936c50d0f2Smckusick regs->dstat = SII_DNE;
8946c50d0f2Smckusick MachEmptyWriteBuffer();
8956c50d0f2Smckusick #ifdef DEBUG
8966c50d0f2Smckusick if (sii_debug > 4)
8976c50d0f2Smckusick printf("DMA amt %d ", i);
8986c50d0f2Smckusick #endif
8996c50d0f2Smckusick switch (comm & SII_PHASE_MSK) {
9006c50d0f2Smckusick case SII_DATA_IN_PHASE:
9016c50d0f2Smckusick /* copy in the data */
9026c50d0f2Smckusick CopyFromBuffer((volatile u_short *)
9036c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex],
9046c50d0f2Smckusick state->buf, i);
9056c50d0f2Smckusick
9066c50d0f2Smckusick case SII_CMD_PHASE:
9076c50d0f2Smckusick case SII_DATA_OUT_PHASE:
9086c50d0f2Smckusick state->buflen -= i;
9096c50d0f2Smckusick }
9106c50d0f2Smckusick }
9116c50d0f2Smckusick
9126c50d0f2Smckusick /* read a one byte status message */
9136c50d0f2Smckusick state->statusByte = msg =
914f327dcccSmckusick sii_GetByte(regs, SII_STATUS_PHASE, 1);
9156c50d0f2Smckusick if (msg < 0) {
9166c50d0f2Smckusick dstat = regs->dstat;
9176c50d0f2Smckusick goto again;
9186c50d0f2Smckusick }
9196c50d0f2Smckusick #ifdef DEBUG
9206c50d0f2Smckusick if (sii_debug > 4)
9216c50d0f2Smckusick printf("Status %x ", msg);
9226c50d0f2Smckusick if (sii_logp > sii_log)
9236c50d0f2Smckusick sii_logp[-1].msg = msg;
9246c50d0f2Smckusick else
9256c50d0f2Smckusick sii_log[NLOG - 1].msg = msg;
9266c50d0f2Smckusick #endif
9276c50d0f2Smckusick
9286c50d0f2Smckusick /* do a quick wait for COMMAND_COMPLETE */
9296c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
9306c50d0f2Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
9316c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) {
9326c50d0f2Smckusick #ifdef DEBUG
9336c50d0f2Smckusick if (sii_debug > 4)
9346c50d0f2Smckusick printf("cnt2 %d\n", i);
9356c50d0f2Smckusick #endif
9366c50d0f2Smckusick goto again;
9376c50d0f2Smckusick }
9386c50d0f2Smckusick break;
9396c50d0f2Smckusick
9406c50d0f2Smckusick case SII_MSG_IN_PHASE:
9416c50d0f2Smckusick /*
9426c50d0f2Smckusick * Save DMA state if DMA didn't finish.
9436c50d0f2Smckusick * Be careful not to save state again after reconnect
9446c50d0f2Smckusick * and see RESTORE_POINTER message.
9456c50d0f2Smckusick * Note that the SII DMA address is not incremented
9466c50d0f2Smckusick * as DMA proceeds.
9476c50d0f2Smckusick */
9486c50d0f2Smckusick if (state->dmaCurPhase > 0) {
9496c50d0f2Smckusick /* save dma registers */
9506c50d0f2Smckusick state->dmaPrevPhase = state->dmaCurPhase;
9516c50d0f2Smckusick state->dmaCurPhase = -1;
9526c50d0f2Smckusick state->dmaCnt = i = regs->dmlotc;
9536c50d0f2Smckusick if (dstat & SII_OBB)
9546c50d0f2Smckusick state->dmaByte = regs->dmabyte;
9556c50d0f2Smckusick if (i == 0)
9566c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH;
9576c50d0f2Smckusick i = state->dmalen - i;
9586c50d0f2Smckusick /* note: no carry from dmaddrl to dmaddrh */
9596c50d0f2Smckusick state->dmaAddrL = regs->dmaddrl + i;
9606c50d0f2Smckusick state->dmaAddrH = regs->dmaddrh;
9616c50d0f2Smckusick regs->comm = comm &
9626c50d0f2Smckusick (SII_STATE_MSK | SII_PHASE_MSK);
9636c50d0f2Smckusick MachEmptyWriteBuffer();
9646c50d0f2Smckusick regs->dstat = SII_DNE;
9656c50d0f2Smckusick MachEmptyWriteBuffer();
9666c50d0f2Smckusick #ifdef DEBUG
9676c50d0f2Smckusick if (sii_debug > 4) {
9686c50d0f2Smckusick printf("SavP dcnt %d dadr %x ",
9696c50d0f2Smckusick state->dmaCnt,
9706c50d0f2Smckusick (state->dmaAddrH << 16) |
9716c50d0f2Smckusick state->dmaAddrL);
9726c50d0f2Smckusick if (((dstat & SII_OBB) != 0) ^
9736c50d0f2Smckusick (state->dmaCnt & 1))
9746c50d0f2Smckusick printf("OBB??? ");
9756c50d0f2Smckusick } else if (sii_debug > 0) {
9766c50d0f2Smckusick if (((dstat & SII_OBB) != 0) ^
9776c50d0f2Smckusick (state->dmaCnt & 1)) {
9786c50d0f2Smckusick printf("sii_DoIntr: OBB??? ds %x cnt %d\n",
9796c50d0f2Smckusick dstat, state->dmaCnt);
9806c50d0f2Smckusick sii_DumpLog();
9816c50d0f2Smckusick }
9826c50d0f2Smckusick }
9836c50d0f2Smckusick #endif
9846c50d0f2Smckusick }
9856c50d0f2Smckusick
9866c50d0f2Smckusick /* read a one byte message */
987f327dcccSmckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 0);
9886c50d0f2Smckusick if (msg < 0) {
9896c50d0f2Smckusick dstat = regs->dstat;
9906c50d0f2Smckusick goto again;
9916c50d0f2Smckusick }
9926c50d0f2Smckusick #ifdef DEBUG
9936c50d0f2Smckusick if (sii_debug > 4)
9946c50d0f2Smckusick printf("MsgIn %x ", msg);
9956c50d0f2Smckusick if (sii_logp > sii_log)
9966c50d0f2Smckusick sii_logp[-1].msg = msg;
9976c50d0f2Smckusick else
9986c50d0f2Smckusick sii_log[NLOG - 1].msg = msg;
9996c50d0f2Smckusick #endif
10006c50d0f2Smckusick
10016c50d0f2Smckusick /* process message */
10026c50d0f2Smckusick switch (msg) {
10036c50d0f2Smckusick case SCSI_COMMAND_COMPLETE:
1004f327dcccSmckusick /* acknowledge last byte */
1005f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1006f327dcccSmckusick (comm & SII_STATE_MSK);
1007f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1008f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1009f327dcccSmckusick regs->dstat = SII_DNE;
1010f327dcccSmckusick MachEmptyWriteBuffer();
10116c50d0f2Smckusick msg = sc->sc_target;
10126c50d0f2Smckusick sc->sc_target = -1;
10136c50d0f2Smckusick /*
10146c50d0f2Smckusick * Wait a short time for disconnect.
10156c50d0f2Smckusick * Don't be fooled if SII_BER happens first.
10166c50d0f2Smckusick * Note: a reselect may happen here.
10176c50d0f2Smckusick */
10186c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat,
10196c50d0f2Smckusick cstat & (SII_RST | SII_SCH),
10206c50d0f2Smckusick SII_WAIT_COUNT, i);
10216c50d0f2Smckusick if ((cstat & (SII_RST | SII_SCH |
10226c50d0f2Smckusick SII_STATE_MSK)) == SII_SCH) {
10236c50d0f2Smckusick regs->cstat = SII_SCH | SII_BER;
10246c50d0f2Smckusick regs->comm = 0;
10256c50d0f2Smckusick MachEmptyWriteBuffer();
10266c50d0f2Smckusick /*
10276c50d0f2Smckusick * Double check that we didn't miss a
10286c50d0f2Smckusick * state change between seeing it and
10296c50d0f2Smckusick * clearing the SII_SCH bit.
10306c50d0f2Smckusick */
10316c50d0f2Smckusick i = regs->cstat;
10326c50d0f2Smckusick if (!(i & SII_SCH) &&
10336c50d0f2Smckusick (i & SII_STATE_MSK) !=
10346c50d0f2Smckusick (cstat & SII_STATE_MSK))
10356c50d0f2Smckusick sii_StateChg(sc, i);
10366c50d0f2Smckusick }
10376c50d0f2Smckusick #ifdef DEBUG
10386c50d0f2Smckusick if (sii_debug > 4)
10396c50d0f2Smckusick printf("cs %x\n", cstat);
10406c50d0f2Smckusick #endif
10416c50d0f2Smckusick sii_CmdDone(sc, msg, 0);
10426c50d0f2Smckusick break;
10436c50d0f2Smckusick
10446c50d0f2Smckusick case SCSI_EXTENDED_MSG:
1045f327dcccSmckusick /* acknowledge last byte */
1046f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1047f327dcccSmckusick (comm & SII_STATE_MSK);
1048f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1049f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1050f327dcccSmckusick regs->dstat = SII_DNE;
1051f327dcccSmckusick MachEmptyWriteBuffer();
10526c50d0f2Smckusick /* read the message length */
1053f327dcccSmckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 1);
10546c50d0f2Smckusick if (msg < 0) {
10556c50d0f2Smckusick dstat = regs->dstat;
10566c50d0f2Smckusick goto again;
10576c50d0f2Smckusick }
1058f327dcccSmckusick sii_buf[1] = msg; /* message length */
10596c50d0f2Smckusick if (msg == 0)
10606c50d0f2Smckusick msg = 256;
1061f327dcccSmckusick /*
1062f327dcccSmckusick * We read and acknowlege all the bytes
1063f327dcccSmckusick * except the last so we can assert ATN
1064f327dcccSmckusick * if needed before acknowledging the last.
1065f327dcccSmckusick */
1066f327dcccSmckusick for (i = 0; i < msg; i++) {
1067f327dcccSmckusick dstat = sii_GetByte(regs,
1068f327dcccSmckusick SII_MSG_IN_PHASE, i < msg - 1);
1069f327dcccSmckusick if ((int)dstat < 0) {
1070f327dcccSmckusick dstat = regs->dstat;
10716c50d0f2Smckusick goto again;
10726c50d0f2Smckusick }
1073f327dcccSmckusick sii_buf[i + 2] = dstat;
1074f327dcccSmckusick }
10756c50d0f2Smckusick
10766c50d0f2Smckusick switch (sii_buf[2]) {
10776c50d0f2Smckusick case SCSI_MODIFY_DATA_PTR:
1078f327dcccSmckusick /* acknowledge last byte */
1079f327dcccSmckusick regs->comm = SII_INXFER |
1080f327dcccSmckusick SII_MSG_IN_PHASE |
1081f327dcccSmckusick (comm & SII_STATE_MSK);
1082f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1083f327dcccSmckusick dstat & SII_DNE,
1084f327dcccSmckusick SII_WAIT_COUNT, i);
1085f327dcccSmckusick regs->dstat = SII_DNE;
1086f327dcccSmckusick MachEmptyWriteBuffer();
10876c50d0f2Smckusick i = (sii_buf[3] << 24) |
10886c50d0f2Smckusick (sii_buf[4] << 16) |
10896c50d0f2Smckusick (sii_buf[5] << 8) |
10906c50d0f2Smckusick sii_buf[6];
10916c50d0f2Smckusick if (state->dmaPrevPhase >= 0) {
10926c50d0f2Smckusick state->dmaAddrL += i;
10936c50d0f2Smckusick state->dmaCnt -= i;
10946c50d0f2Smckusick }
10956c50d0f2Smckusick break;
10966c50d0f2Smckusick
10976c50d0f2Smckusick case SCSI_SYNCHRONOUS_XFER:
1098f327dcccSmckusick /*
1099f327dcccSmckusick * Acknowledge last byte and
1100f327dcccSmckusick * signal a request for MSG_OUT.
1101f327dcccSmckusick */
1102f327dcccSmckusick regs->comm = SII_INXFER | SII_ATN |
1103f327dcccSmckusick SII_MSG_IN_PHASE |
1104f327dcccSmckusick (comm & SII_STATE_MSK);
1105f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1106f327dcccSmckusick dstat & SII_DNE,
1107f327dcccSmckusick SII_WAIT_COUNT, i);
1108f327dcccSmckusick regs->dstat = SII_DNE;
1109f327dcccSmckusick MachEmptyWriteBuffer();
11106c50d0f2Smckusick sii_DoSync(regs, state);
11116c50d0f2Smckusick break;
11126c50d0f2Smckusick
11136c50d0f2Smckusick default:
11146c50d0f2Smckusick reject:
1115f327dcccSmckusick /*
1116f327dcccSmckusick * Acknowledge last byte and
1117f327dcccSmckusick * signal a request for MSG_OUT.
1118f327dcccSmckusick */
11196c50d0f2Smckusick regs->comm = SII_INXFER | SII_ATN |
1120f327dcccSmckusick SII_MSG_IN_PHASE |
1121f327dcccSmckusick (comm & SII_STATE_MSK);
11226c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1123f327dcccSmckusick dstat & SII_DNE,
1124f327dcccSmckusick SII_WAIT_COUNT, i);
1125f327dcccSmckusick regs->dstat = SII_DNE;
1126f327dcccSmckusick MachEmptyWriteBuffer();
1127f327dcccSmckusick
1128f327dcccSmckusick /* wait for MSG_OUT phase */
1129f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1130f327dcccSmckusick dstat & SII_TBE,
11316c50d0f2Smckusick SII_WAIT_COUNT, i);
11326c50d0f2Smckusick
1133f327dcccSmckusick /* send a reject message */
1134f327dcccSmckusick regs->data = SCSI_MESSAGE_REJECT;
1135f327dcccSmckusick regs->comm = SII_INXFER |
1136f327dcccSmckusick (regs->cstat & SII_STATE_MSK) |
1137f327dcccSmckusick SII_MSG_OUT_PHASE;
1138f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1139f327dcccSmckusick dstat & SII_DNE,
1140f327dcccSmckusick SII_WAIT_COUNT, i);
11416c50d0f2Smckusick regs->dstat = SII_DNE;
11426c50d0f2Smckusick MachEmptyWriteBuffer();
11436c50d0f2Smckusick }
11446c50d0f2Smckusick break;
11456c50d0f2Smckusick
11466c50d0f2Smckusick case SCSI_SAVE_DATA_POINTER:
11476c50d0f2Smckusick case SCSI_RESTORE_POINTERS:
1148f327dcccSmckusick /* acknowledge last byte */
1149f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1150f327dcccSmckusick (comm & SII_STATE_MSK);
1151f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1152f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1153f327dcccSmckusick regs->dstat = SII_DNE;
1154f327dcccSmckusick MachEmptyWriteBuffer();
11556c50d0f2Smckusick /* wait a short time for another msg */
11566c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
11576c50d0f2Smckusick dstat & (SII_CI | SII_DI),
11586c50d0f2Smckusick SII_WAIT_COUNT, i);
11596c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) {
11606c50d0f2Smckusick #ifdef DEBUG
11616c50d0f2Smckusick if (sii_debug > 4)
11626c50d0f2Smckusick printf("cnt %d\n", i);
11636c50d0f2Smckusick #endif
11646c50d0f2Smckusick goto again;
11656c50d0f2Smckusick }
11666c50d0f2Smckusick break;
11676c50d0f2Smckusick
11686c50d0f2Smckusick case SCSI_DISCONNECT:
1169f327dcccSmckusick /* acknowledge last byte */
1170f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1171f327dcccSmckusick (comm & SII_STATE_MSK);
1172f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1173f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1174f327dcccSmckusick regs->dstat = SII_DNE;
1175f327dcccSmckusick MachEmptyWriteBuffer();
11766c50d0f2Smckusick state->prevComm = comm;
11776c50d0f2Smckusick #ifdef DEBUG
11786c50d0f2Smckusick if (sii_debug > 4)
11796c50d0f2Smckusick printf("disconn %d ", sc->sc_target);
11806c50d0f2Smckusick #endif
11816c50d0f2Smckusick /*
11826c50d0f2Smckusick * Wait a short time for disconnect.
11836c50d0f2Smckusick * Don't be fooled if SII_BER happens first.
11846c50d0f2Smckusick * Note: a reselect may happen here.
11856c50d0f2Smckusick */
11866c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat,
11876c50d0f2Smckusick cstat & (SII_RST | SII_SCH),
11886c50d0f2Smckusick SII_WAIT_COUNT, i);
11896c50d0f2Smckusick if ((cstat & (SII_RST | SII_SCH |
11906c50d0f2Smckusick SII_STATE_MSK)) != SII_SCH) {
11916c50d0f2Smckusick #ifdef DEBUG
11926c50d0f2Smckusick if (sii_debug > 4)
11936c50d0f2Smckusick printf("cnt %d\n", i);
11946c50d0f2Smckusick #endif
11956c50d0f2Smckusick dstat = regs->dstat;
11966c50d0f2Smckusick goto again;
11976c50d0f2Smckusick }
11986c50d0f2Smckusick regs->cstat = SII_SCH | SII_BER;
11996c50d0f2Smckusick regs->comm = 0;
12006c50d0f2Smckusick MachEmptyWriteBuffer();
12016c50d0f2Smckusick sc->sc_target = -1;
12026c50d0f2Smckusick /*
12036c50d0f2Smckusick * Double check that we didn't miss a state
12046c50d0f2Smckusick * change between seeing it and clearing
12056c50d0f2Smckusick * the SII_SCH bit.
12066c50d0f2Smckusick */
12076c50d0f2Smckusick i = regs->cstat;
12086c50d0f2Smckusick if (!(i & SII_SCH) && (i & SII_STATE_MSK) !=
12096c50d0f2Smckusick (cstat & SII_STATE_MSK))
12106c50d0f2Smckusick sii_StateChg(sc, i);
12116c50d0f2Smckusick break;
12126c50d0f2Smckusick
12136c50d0f2Smckusick case SCSI_MESSAGE_REJECT:
1214f327dcccSmckusick /* acknowledge last byte */
1215f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1216f327dcccSmckusick (comm & SII_STATE_MSK);
1217f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1218f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1219f327dcccSmckusick regs->dstat = SII_DNE;
1220f327dcccSmckusick MachEmptyWriteBuffer();
12216c50d0f2Smckusick printf("sii%d: device %d: message reject.\n",
12226c50d0f2Smckusick sc - sii_softc, sc->sc_target);
1223f327dcccSmckusick break;
12246c50d0f2Smckusick
12256c50d0f2Smckusick default:
12266c50d0f2Smckusick if (!(msg & SCSI_IDENTIFY)) {
1227f327dcccSmckusick printf("sii%d: device %d: couldn't handle message 0x%x... rejecting.\n",
12286c50d0f2Smckusick sc - sii_softc, sc->sc_target,
12296c50d0f2Smckusick msg);
12306c50d0f2Smckusick #ifdef DEBUG
12316c50d0f2Smckusick sii_DumpLog();
12326c50d0f2Smckusick #endif
1233f327dcccSmckusick goto reject;
12346c50d0f2Smckusick }
1235f327dcccSmckusick /* acknowledge last byte */
1236f327dcccSmckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE |
1237f327dcccSmckusick (comm & SII_STATE_MSK);
1238f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat,
1239f327dcccSmckusick dstat & SII_DNE, SII_WAIT_COUNT, i);
1240f327dcccSmckusick regs->dstat = SII_DNE;
1241f327dcccSmckusick MachEmptyWriteBuffer();
12426c50d0f2Smckusick /* may want to check LUN some day */
12436c50d0f2Smckusick /* wait a short time for another msg */
12446c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
12456c50d0f2Smckusick dstat & (SII_CI | SII_DI),
12466c50d0f2Smckusick SII_WAIT_COUNT, i);
12476c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) {
12486c50d0f2Smckusick #ifdef DEBUG
12496c50d0f2Smckusick if (sii_debug > 4)
12506c50d0f2Smckusick printf("cnt %d\n", i);
12516c50d0f2Smckusick #endif
12526c50d0f2Smckusick goto again;
12536c50d0f2Smckusick }
12546c50d0f2Smckusick }
12556c50d0f2Smckusick break;
12566c50d0f2Smckusick
12576c50d0f2Smckusick case SII_MSG_OUT_PHASE:
12586c50d0f2Smckusick #ifdef DEBUG
12596c50d0f2Smckusick if (sii_debug > 4)
12606c50d0f2Smckusick printf("MsgOut\n");
12616c50d0f2Smckusick #endif
1262f327dcccSmckusick printf("MsgOut %x\n", state->flags); /* XXX */
12636c50d0f2Smckusick
1264f327dcccSmckusick /*
1265f327dcccSmckusick * Check for parity error.
1266f327dcccSmckusick * Hardware will automatically set ATN
1267f327dcccSmckusick * to request the device for a MSG_OUT phase.
1268f327dcccSmckusick */
1269f327dcccSmckusick if (state->flags & PARITY_ERR) {
1270f327dcccSmckusick state->flags &= ~PARITY_ERR;
1271f327dcccSmckusick regs->data = SCSI_MESSAGE_PARITY_ERROR;
1272f327dcccSmckusick } else
12736c50d0f2Smckusick regs->data = SCSI_NO_OP;
12746c50d0f2Smckusick regs->comm = SII_INXFER | (comm & SII_STATE_MSK) |
12756c50d0f2Smckusick SII_MSG_OUT_PHASE;
12766c50d0f2Smckusick MachEmptyWriteBuffer();
12776c50d0f2Smckusick
12786c50d0f2Smckusick /* wait a short time for XFER complete */
12796c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
12806c50d0f2Smckusick SII_WAIT_COUNT, i);
12816c50d0f2Smckusick #ifdef DEBUG
12826c50d0f2Smckusick if (sii_debug > 4)
12836c50d0f2Smckusick printf("ds %x i %d\n", dstat, i);
12846c50d0f2Smckusick #endif
12856c50d0f2Smckusick /* just clear the DNE bit and check errors later */
12866c50d0f2Smckusick if (dstat & SII_DNE) {
12876c50d0f2Smckusick regs->dstat = SII_DNE;
12886c50d0f2Smckusick MachEmptyWriteBuffer();
12896c50d0f2Smckusick }
12906c50d0f2Smckusick break;
12916c50d0f2Smckusick
12926c50d0f2Smckusick default:
12936c50d0f2Smckusick printf("sii%d: Couldn't handle phase %d... ignoring.\n",
12946c50d0f2Smckusick sc - sii_softc, dstat & SII_PHASE_MSK);
12956c50d0f2Smckusick }
12966c50d0f2Smckusick }
12976c50d0f2Smckusick
12986c50d0f2Smckusick #ifdef DEBUG
12996c50d0f2Smckusick if (sii_debug > 3)
13006c50d0f2Smckusick printf("\n");
13016c50d0f2Smckusick #endif
13026c50d0f2Smckusick /*
13036c50d0f2Smckusick * Check to make sure we won't be interrupted again.
13046c50d0f2Smckusick * Deglitch dstat register.
13056c50d0f2Smckusick */
13066c50d0f2Smckusick msg = regs->dstat;
13076c50d0f2Smckusick while (msg != (dstat = regs->dstat))
13086c50d0f2Smckusick msg = dstat;
13096c50d0f2Smckusick if (dstat & (SII_CI | SII_DI))
13106c50d0f2Smckusick goto again;
13116c50d0f2Smckusick
13126c50d0f2Smckusick if (sc->sc_target < 0) {
13136c50d0f2Smckusick /* look for another device that is ready */
13146c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) {
13156c50d0f2Smckusick /* don't restart a disconnected command */
13166c50d0f2Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
13176c50d0f2Smckusick continue;
13186c50d0f2Smckusick sii_StartCmd(sc, i);
13196c50d0f2Smckusick break;
13206c50d0f2Smckusick }
13216c50d0f2Smckusick }
13226c50d0f2Smckusick return;
13236c50d0f2Smckusick
13246c50d0f2Smckusick abort:
13256c50d0f2Smckusick /* jump here to abort the current command */
13266c50d0f2Smckusick printf("sii%d: device %d: current command terminated\n",
13276c50d0f2Smckusick sc - sii_softc, sc->sc_target);
13286c50d0f2Smckusick #ifdef DEBUG
13296c50d0f2Smckusick sii_DumpLog();
13306c50d0f2Smckusick #endif
13316c50d0f2Smckusick
13326c50d0f2Smckusick if ((cstat = regs->cstat) & SII_CON) {
13336c50d0f2Smckusick /* try to send an abort msg for awhile */
13346c50d0f2Smckusick regs->dstat = SII_DNE;
13356c50d0f2Smckusick regs->data = SCSI_ABORT;
13366c50d0f2Smckusick regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) |
13376c50d0f2Smckusick SII_MSG_OUT_PHASE;
13386c50d0f2Smckusick MachEmptyWriteBuffer();
13396c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
13406c50d0f2Smckusick (dstat & (SII_DNE | SII_PHASE_MSK)) ==
13416c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE),
13426c50d0f2Smckusick 2 * SII_WAIT_COUNT, i);
13436c50d0f2Smckusick #ifdef DEBUG
13446c50d0f2Smckusick if (sii_debug > 0)
13456c50d0f2Smckusick printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);
13466c50d0f2Smckusick #endif
13476c50d0f2Smckusick if (dstat & (SII_DNE | SII_PHASE_MSK) ==
13486c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) {
13496c50d0f2Smckusick /* disconnect if command in progress */
13506c50d0f2Smckusick regs->comm = SII_DISCON;
13516c50d0f2Smckusick MachEmptyWriteBuffer();
13526c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat,
13536c50d0f2Smckusick !(cstat & SII_CON), SII_WAIT_COUNT, i);
13546c50d0f2Smckusick }
13556c50d0f2Smckusick } else {
13566c50d0f2Smckusick #ifdef DEBUG
13576c50d0f2Smckusick if (sii_debug > 0)
13586c50d0f2Smckusick printf("Abort: cs %x\n", cstat);
13596c50d0f2Smckusick #endif
13606c50d0f2Smckusick }
13616c50d0f2Smckusick regs->cstat = 0xffff;
13626c50d0f2Smckusick regs->dstat = 0xffff;
13636c50d0f2Smckusick regs->comm = 0;
13646c50d0f2Smckusick MachEmptyWriteBuffer();
13656c50d0f2Smckusick
13666c50d0f2Smckusick i = sc->sc_target;
13676c50d0f2Smckusick sc->sc_target = -1;
13686c50d0f2Smckusick sii_CmdDone(sc, i, EIO);
13696c50d0f2Smckusick #ifdef DEBUG
13706c50d0f2Smckusick if (sii_debug > 4)
13716c50d0f2Smckusick printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);
13726c50d0f2Smckusick #endif
13736c50d0f2Smckusick }
13746c50d0f2Smckusick
13756c50d0f2Smckusick static void
sii_StateChg(sc,cstat)13766c50d0f2Smckusick sii_StateChg(sc, cstat)
13776c50d0f2Smckusick register struct siisoftc *sc;
1378f327dcccSmckusick register u_int cstat;
13796c50d0f2Smckusick {
13806c50d0f2Smckusick register SIIRegs *regs = sc->sc_regs;
13816c50d0f2Smckusick register State *state;
13826c50d0f2Smckusick register int i;
13836c50d0f2Smckusick
13846c50d0f2Smckusick #ifdef DEBUG
13856c50d0f2Smckusick if (sii_debug > 4)
13866c50d0f2Smckusick printf("SCH: ");
13876c50d0f2Smckusick #endif
13886c50d0f2Smckusick
13896c50d0f2Smckusick switch (cstat & SII_STATE_MSK) {
13906c50d0f2Smckusick case 0:
13916c50d0f2Smckusick /* disconnect */
13926c50d0f2Smckusick i = sc->sc_target;
13936c50d0f2Smckusick sc->sc_target = -1;
13946c50d0f2Smckusick #ifdef DEBUG
13956c50d0f2Smckusick if (sii_debug > 4)
13966c50d0f2Smckusick printf("disconn %d ", i);
13976c50d0f2Smckusick #endif
13986c50d0f2Smckusick if (i >= 0 && !sc->sc_st[i].prevComm) {
13996c50d0f2Smckusick printf("sii%d: device %d: spurrious disconnect (%d)\n",
14006c50d0f2Smckusick sc - sii_softc, i, regs->slcsr);
14016c50d0f2Smckusick sc->sc_st[i].prevComm = 0;
14026c50d0f2Smckusick }
14036c50d0f2Smckusick break;
14046c50d0f2Smckusick
14056c50d0f2Smckusick case SII_CON:
14066c50d0f2Smckusick /* connected as initiator */
14076c50d0f2Smckusick i = regs->slcsr;
14086c50d0f2Smckusick if (sc->sc_target == i)
14096c50d0f2Smckusick break;
14106c50d0f2Smckusick printf("sii%d: device %d: connect to device %d??\n",
14116c50d0f2Smckusick sc - sii_softc, sc->sc_target, i);
14126c50d0f2Smckusick sc->sc_target = i;
14136c50d0f2Smckusick break;
14146c50d0f2Smckusick
14156c50d0f2Smckusick case SII_DST:
14166c50d0f2Smckusick /*
14176c50d0f2Smckusick * Wait for CON to become valid,
14186c50d0f2Smckusick * chip is slow sometimes.
14196c50d0f2Smckusick */
14206c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat,
14216c50d0f2Smckusick cstat & SII_CON, SII_WAIT_COUNT, i);
14226c50d0f2Smckusick if (!(cstat & SII_CON))
14236c50d0f2Smckusick panic("sii resel");
14246c50d0f2Smckusick /* FALLTHROUGH */
14256c50d0f2Smckusick
14266c50d0f2Smckusick case SII_CON | SII_DST:
14276c50d0f2Smckusick /*
14286c50d0f2Smckusick * Its a reselection. Save the ID and wait for
14296c50d0f2Smckusick * interrupts to tell us what to do next
14306c50d0f2Smckusick * (should be MSG_IN of IDENTIFY).
14316c50d0f2Smckusick * NOTE: sc_target may be >= 0 if we were in
14326c50d0f2Smckusick * the process of trying to start a command
14336c50d0f2Smckusick * and were reselected before the select
14346c50d0f2Smckusick * command finished.
14356c50d0f2Smckusick */
14366c50d0f2Smckusick sc->sc_target = i = regs->destat;
14376c50d0f2Smckusick state = &sc->sc_st[i];
1438f327dcccSmckusick regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE;
1439f327dcccSmckusick regs->dmctrl = state->dmaReqAck;
1440f327dcccSmckusick MachEmptyWriteBuffer();
14416c50d0f2Smckusick if (!state->prevComm) {
14426c50d0f2Smckusick printf("sii%d: device %d: spurrious reselection\n",
14436c50d0f2Smckusick sc - sii_softc, i);
14446c50d0f2Smckusick break;
14456c50d0f2Smckusick }
14466c50d0f2Smckusick state->prevComm = 0;
14476c50d0f2Smckusick #ifdef DEBUG
14486c50d0f2Smckusick if (sii_debug > 4)
14496c50d0f2Smckusick printf("resel %d ", sc->sc_target);
14506c50d0f2Smckusick #endif
14516c50d0f2Smckusick break;
14526c50d0f2Smckusick
14536c50d0f2Smckusick #ifdef notyet
14546c50d0f2Smckusick case SII_DST | SII_TGT:
14556c50d0f2Smckusick case SII_CON | SII_DST | SII_TGT:
14566c50d0f2Smckusick /* connected as target */
14576c50d0f2Smckusick printf("sii%d: Selected by device %d as target!!\n",
14586c50d0f2Smckusick sc - sii_softc, regs->destat);
14596c50d0f2Smckusick regs->comm = SII_DISCON;
14606c50d0f2Smckusick MachEmptyWriteBuffer();
14616c50d0f2Smckusick SII_WAIT_UNTIL(!(regs->cstat & SII_CON),
14626c50d0f2Smckusick SII_WAIT_COUNT, i);
14636c50d0f2Smckusick regs->cstat = 0xffff;
14646c50d0f2Smckusick regs->dstat = 0xffff;
14656c50d0f2Smckusick regs->comm = 0;
14666c50d0f2Smckusick break;
14676c50d0f2Smckusick #endif
14686c50d0f2Smckusick
14696c50d0f2Smckusick default:
14706c50d0f2Smckusick printf("sii%d: Unknown state change (cs %x)!!\n",
14716c50d0f2Smckusick sc - sii_softc, cstat);
14726c50d0f2Smckusick #ifdef DEBUG
14736c50d0f2Smckusick sii_DumpLog();
14746c50d0f2Smckusick #endif
14756c50d0f2Smckusick }
14766c50d0f2Smckusick }
14776c50d0f2Smckusick
14786c50d0f2Smckusick /*
14796c50d0f2Smckusick * Read one byte of data.
1480f327dcccSmckusick * If 'ack' is true, acknowledge the byte.
14816c50d0f2Smckusick */
14826c50d0f2Smckusick static int
sii_GetByte(regs,phase,ack)1483f327dcccSmckusick sii_GetByte(regs, phase, ack)
14846c50d0f2Smckusick register SIIRegs *regs;
1485f327dcccSmckusick int phase, ack;
14866c50d0f2Smckusick {
1487f327dcccSmckusick register u_int dstat;
1488f327dcccSmckusick register u_int state;
1489f327dcccSmckusick register int i;
1490f327dcccSmckusick register int data;
14916c50d0f2Smckusick
14926c50d0f2Smckusick dstat = regs->dstat;
14936c50d0f2Smckusick state = regs->cstat & SII_STATE_MSK;
14946c50d0f2Smckusick if (!(dstat & SII_IBF) || (dstat & SII_MIS)) {
14956c50d0f2Smckusick regs->comm = state | phase;
14966c50d0f2Smckusick MachEmptyWriteBuffer();
14976c50d0f2Smckusick /* wait a short time for IBF */
14986c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF,
14996c50d0f2Smckusick SII_WAIT_COUNT, i);
15006c50d0f2Smckusick #ifdef DEBUG
15016c50d0f2Smckusick if (!(dstat & SII_IBF))
15026c50d0f2Smckusick printf("status no IBF\n");
15036c50d0f2Smckusick #endif
15046c50d0f2Smckusick }
1505f327dcccSmckusick if (dstat & SII_DNE) { /* XXX */
15066c50d0f2Smckusick printf("sii_GetByte: DNE set 5\n");
1507*de6ace06Smckusick #ifdef DEBUG
15086c50d0f2Smckusick sii_DumpLog();
1509*de6ace06Smckusick #endif
15106c50d0f2Smckusick regs->dstat = SII_DNE;
15116c50d0f2Smckusick }
1512f327dcccSmckusick data = regs->data;
1513f327dcccSmckusick /* check for parity error */
1514f327dcccSmckusick if (dstat & SII_IPE) {
1515f327dcccSmckusick #ifdef DEBUG
1516f327dcccSmckusick if (sii_debug > 4)
1517f327dcccSmckusick printf("cnt0 %d\n", i);
1518f327dcccSmckusick #endif
1519f327dcccSmckusick printf("sii_GetByte: data %x ?? ds %x cm %x i %d\n",
1520f327dcccSmckusick data, dstat, regs->comm, i); /* XXX */
1521f327dcccSmckusick data = -1;
1522f327dcccSmckusick ack = 1;
1523f327dcccSmckusick }
1524f327dcccSmckusick
1525f327dcccSmckusick if (ack) {
15266c50d0f2Smckusick regs->comm = SII_INXFER | state | phase;
15276c50d0f2Smckusick MachEmptyWriteBuffer();
15286c50d0f2Smckusick
15296c50d0f2Smckusick /* wait a short time for XFER complete */
15306c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
15316c50d0f2Smckusick SII_WAIT_COUNT, i);
15326c50d0f2Smckusick
1533f327dcccSmckusick /* clear the DNE */
1534f327dcccSmckusick if (dstat & SII_DNE) {
15356c50d0f2Smckusick regs->dstat = SII_DNE;
15366c50d0f2Smckusick MachEmptyWriteBuffer();
1537f327dcccSmckusick }
1538f327dcccSmckusick }
1539f327dcccSmckusick
15406c50d0f2Smckusick return (data);
15416c50d0f2Smckusick }
15426c50d0f2Smckusick
15436c50d0f2Smckusick /*
15446c50d0f2Smckusick * Exchange messages to initiate synchronous data transfers.
15456c50d0f2Smckusick */
15466c50d0f2Smckusick static void
sii_DoSync(regs,state)15476c50d0f2Smckusick sii_DoSync(regs, state)
15486c50d0f2Smckusick register SIIRegs *regs;
15496c50d0f2Smckusick register State *state;
15506c50d0f2Smckusick {
1551f327dcccSmckusick register u_int dstat, comm;
1552f327dcccSmckusick register int i, j;
1553f327dcccSmckusick u_int len;
15546c50d0f2Smckusick
1555f327dcccSmckusick #ifdef DEBUG
1556f327dcccSmckusick if (sii_debug)
1557f327dcccSmckusick printf("sii_DoSync: len %d per %d req/ack %d\n",
1558f327dcccSmckusick sii_buf[1], sii_buf[3], sii_buf[4]);
1559f327dcccSmckusick #endif
1560f327dcccSmckusick
1561f327dcccSmckusick /* SII chip can only handle a minimum transfer period of ??? */
1562f327dcccSmckusick if (sii_buf[3] < 64)
1563f327dcccSmckusick sii_buf[3] = 64;
1564f327dcccSmckusick /* SII chip can only handle a maximum REQ/ACK offset of 3 */
15656c50d0f2Smckusick len = sii_buf[4];
15666c50d0f2Smckusick if (len > 3)
1567f327dcccSmckusick len = 3;
15686c50d0f2Smckusick
15696c50d0f2Smckusick sii_buf[0] = SCSI_EXTENDED_MSG;
15706c50d0f2Smckusick sii_buf[1] = 3; /* message length */
15716c50d0f2Smckusick sii_buf[2] = SCSI_SYNCHRONOUS_XFER;
15726c50d0f2Smckusick sii_buf[4] = len;
1573f327dcccSmckusick #if 1
1574f327dcccSmckusick comm = SII_INXFER | SII_ATN | SII_MSG_OUT_PHASE |
1575f327dcccSmckusick (regs->cstat & SII_STATE_MSK);
1576f327dcccSmckusick regs->comm = comm & ~SII_INXFER;
1577f327dcccSmckusick for (j = 0; j < 5; j++) {
1578f327dcccSmckusick /* wait for target to request the next byte */
1579f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_TBE,
1580f327dcccSmckusick SII_WAIT_COUNT, i);
1581f327dcccSmckusick if (!(dstat & SII_TBE) ||
1582f327dcccSmckusick (dstat & SII_PHASE_MSK) != SII_MSG_OUT_PHASE) {
1583f327dcccSmckusick printf("sii_DoSync: TBE? ds %x cm %x i %d\n",
1584f327dcccSmckusick dstat, comm, i); /* XXX */
1585f327dcccSmckusick return;
1586f327dcccSmckusick }
1587f327dcccSmckusick
1588f327dcccSmckusick /* the last message byte should have ATN off */
1589f327dcccSmckusick if (j == 4)
1590f327dcccSmckusick comm &= ~SII_ATN;
1591f327dcccSmckusick
1592f327dcccSmckusick regs->data = sii_buf[j];
1593f327dcccSmckusick regs->comm = comm;
1594f327dcccSmckusick MachEmptyWriteBuffer();
1595f327dcccSmckusick
1596f327dcccSmckusick /* wait a short time for XFER complete */
1597f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1598f327dcccSmckusick SII_WAIT_COUNT, i);
1599f327dcccSmckusick
1600f327dcccSmckusick if (!(dstat & SII_DNE)) {
1601f327dcccSmckusick printf("sii_DoSync: DNE? ds %x cm %x i %d\n",
1602f327dcccSmckusick dstat, comm, i); /* XXX */
1603f327dcccSmckusick return;
1604f327dcccSmckusick }
1605f327dcccSmckusick
1606f327dcccSmckusick /* clear the DNE, other errors handled later */
1607f327dcccSmckusick regs->dstat = SII_DNE;
1608f327dcccSmckusick MachEmptyWriteBuffer();
1609f327dcccSmckusick }
1610f327dcccSmckusick #else
16116c50d0f2Smckusick CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5);
1612f327dcccSmckusick printf("sii_DoSync: %x %x %x ds %x\n",
1613f327dcccSmckusick ((volatile u_short *)SII_BUF_ADDR)[0],
1614f327dcccSmckusick ((volatile u_short *)SII_BUF_ADDR)[2],
1615f327dcccSmckusick ((volatile u_short *)SII_BUF_ADDR)[4],
1616f327dcccSmckusick regs->dstat); /* XXX */
1617f327dcccSmckusick regs->dmaddrl = (u_short)(SII_BUF_ADDR >> 1);
1618f327dcccSmckusick regs->dmaddrh = (u_short)(SII_BUF_ADDR >> 17) & 03;
16196c50d0f2Smckusick regs->dmlotc = 5;
16206c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | SII_ATN |
16216c50d0f2Smckusick (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE;
16226c50d0f2Smckusick MachEmptyWriteBuffer();
16236c50d0f2Smckusick
16246c50d0f2Smckusick /* wait a short time for XFER complete */
16256c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat,
16266c50d0f2Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ),
16276c50d0f2Smckusick SII_WAIT_COUNT, i);
16286c50d0f2Smckusick
16296c50d0f2Smckusick if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) {
16306c50d0f2Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
16316c50d0f2Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */
1632*de6ace06Smckusick #ifdef DEBUG
16336c50d0f2Smckusick sii_DumpLog(); /* XXX */
1634*de6ace06Smckusick #endif
16356c50d0f2Smckusick return;
16366c50d0f2Smckusick }
16376c50d0f2Smckusick /* clear the DNE, other errors handled later */
16386c50d0f2Smckusick regs->dstat = SII_DNE;
16396c50d0f2Smckusick MachEmptyWriteBuffer();
1640f327dcccSmckusick #endif
1641f327dcccSmckusick
1642f327dcccSmckusick #if 0
1643f327dcccSmckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI),
1644f327dcccSmckusick SII_WAIT_COUNT, i);
1645f327dcccSmckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
1646f327dcccSmckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */
1647f327dcccSmckusick #endif
16486c50d0f2Smckusick
16496c50d0f2Smckusick state->dmaReqAck = len;
16506c50d0f2Smckusick }
16516c50d0f2Smckusick
16526c50d0f2Smckusick /*
16536c50d0f2Smckusick * Issue the sequence of commands to the controller to start DMA.
16546c50d0f2Smckusick * NOTE: the data buffer should be word-aligned for DMA out.
16556c50d0f2Smckusick */
16566c50d0f2Smckusick static void
sii_StartDMA(regs,phase,dmaAddr,size)16576c50d0f2Smckusick sii_StartDMA(regs, phase, dmaAddr, size)
16586c50d0f2Smckusick register SIIRegs *regs; /* which SII to use */
16596c50d0f2Smckusick int phase; /* phase to send/receive data */
16606c50d0f2Smckusick u_short *dmaAddr; /* DMA buffer address */
16616c50d0f2Smckusick int size; /* # of bytes to transfer */
16626c50d0f2Smckusick {
16636c50d0f2Smckusick
16646c50d0f2Smckusick if (regs->dstat & SII_DNE) { /* XXX */
1665f327dcccSmckusick regs->dstat = SII_DNE;
16666c50d0f2Smckusick printf("sii_StartDMA: DNE set\n");
1667*de6ace06Smckusick #ifdef DEBUG
16686c50d0f2Smckusick sii_DumpLog();
1669*de6ace06Smckusick #endif
16706c50d0f2Smckusick }
1671f327dcccSmckusick regs->dmaddrl = ((u_long)dmaAddr >> 1);
1672f327dcccSmckusick regs->dmaddrh = ((u_long)dmaAddr >> 17) & 03;
16736c50d0f2Smckusick regs->dmlotc = size;
16746c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) |
16756c50d0f2Smckusick phase;
16766c50d0f2Smckusick MachEmptyWriteBuffer();
16776c50d0f2Smckusick
16786c50d0f2Smckusick #ifdef DEBUG
16796c50d0f2Smckusick if (sii_debug > 5) {
16806c50d0f2Smckusick printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n",
16816c50d0f2Smckusick regs->cstat, regs->dstat, regs->comm, size);
16826c50d0f2Smckusick }
16836c50d0f2Smckusick #endif
16846c50d0f2Smckusick }
16856c50d0f2Smckusick
16866c50d0f2Smckusick /*
16876c50d0f2Smckusick * Call the device driver's 'done' routine to let it know the command is done.
16886c50d0f2Smckusick * The 'done' routine may try to start another command.
16896c50d0f2Smckusick * To be fair, we should start pending commands for other devices
16906c50d0f2Smckusick * before allowing the same device to start another command.
16916c50d0f2Smckusick */
16926c50d0f2Smckusick static void
sii_CmdDone(sc,target,error)16936c50d0f2Smckusick sii_CmdDone(sc, target, error)
16946c50d0f2Smckusick register struct siisoftc *sc; /* which SII to use */
16956c50d0f2Smckusick int target; /* which device is done */
16966c50d0f2Smckusick int error; /* error code if any errors */
16976c50d0f2Smckusick {
16986c50d0f2Smckusick register ScsiCmd *scsicmd;
16996c50d0f2Smckusick register int i;
17006c50d0f2Smckusick
17016c50d0f2Smckusick scsicmd = sc->sc_cmd[target];
17026c50d0f2Smckusick #ifdef DIAGNOSTIC
17036c50d0f2Smckusick if (target < 0 || !scsicmd)
17046c50d0f2Smckusick panic("sii_CmdDone");
17056c50d0f2Smckusick #endif
17066c50d0f2Smckusick sc->sc_cmd[target] = (ScsiCmd *)0;
17076c50d0f2Smckusick #ifdef DEBUG
17086c50d0f2Smckusick if (sii_debug > 1) {
17096c50d0f2Smckusick printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n",
17106c50d0f2Smckusick scsicmd->sd->sd_driver->d_name, target,
17116c50d0f2Smckusick scsicmd->cmd[0], error, sc->sc_st[target].buflen);
17126c50d0f2Smckusick }
17136c50d0f2Smckusick #endif
17146c50d0f2Smckusick
17156c50d0f2Smckusick /* look for another device that is ready */
17166c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) {
17176c50d0f2Smckusick /* don't restart a disconnected command */
17186c50d0f2Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
17196c50d0f2Smckusick continue;
17206c50d0f2Smckusick sii_StartCmd(sc, i);
17216c50d0f2Smckusick break;
17226c50d0f2Smckusick }
17236c50d0f2Smckusick
17246c50d0f2Smckusick (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error,
17256c50d0f2Smckusick sc->sc_st[target].buflen, sc->sc_st[target].statusByte);
17266c50d0f2Smckusick }
17276c50d0f2Smckusick
17286c50d0f2Smckusick #ifdef DEBUG
sii_DumpLog()17296c50d0f2Smckusick sii_DumpLog()
17306c50d0f2Smckusick {
17316c50d0f2Smckusick register struct sii_log *lp;
17326c50d0f2Smckusick
17336c50d0f2Smckusick printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn,
17346c50d0f2Smckusick sii_debug_sz);
1735978841aeSmckusick lp = sii_logp;
1736978841aeSmckusick do {
1737f327dcccSmckusick printf("target %d cs %x ds %x cm %x msg %x rlen %x dlen %x\n",
1738f327dcccSmckusick lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg,
1739f327dcccSmckusick lp->rlen, lp->dlen);
17406c50d0f2Smckusick if (++lp >= &sii_log[NLOG])
17416c50d0f2Smckusick lp = sii_log;
1742978841aeSmckusick } while (lp != sii_logp);
17436c50d0f2Smckusick }
17446c50d0f2Smckusick #endif
17456c50d0f2Smckusick #endif
1746