152130Smckusick /* 252130Smckusick * Copyright (c) 1992 Regents of the University of California. 352130Smckusick * All rights reserved. 452130Smckusick * 552130Smckusick * This code is derived from software contributed to Berkeley by 652130Smckusick * Ralph Campbell. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*56522Sbostic * @(#)sii.c 7.5 (Berkeley) 10/11/92 1152130Smckusick * 1252130Smckusick * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c, 1352754Sralph * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)"; 1452130Smckusick */ 1552130Smckusick 1652130Smckusick #include "sii.h" 1752130Smckusick #if NSII > 0 1852130Smckusick /* 1952130Smckusick * SCSI interface driver 2052130Smckusick */ 21*56522Sbostic #include <sys/param.h> 22*56522Sbostic #include <sys/systm.h> 23*56522Sbostic #include <sys/dkstat.h> 24*56522Sbostic #include <sys/buf.h> 25*56522Sbostic #include <sys/conf.h> 26*56522Sbostic #include <sys/errno.h> 2752130Smckusick 28*56522Sbostic #include <machine/machConst.h> 29*56522Sbostic #include <mips/dev/device.h> 30*56522Sbostic #include <mips/dev/scsi.h> 31*56522Sbostic #include <mips/dev/siireg.h> 3252130Smckusick 3352130Smckusick int siiprobe(); 3452130Smckusick void siistart(); 3552130Smckusick struct driver siidriver = { 3652130Smckusick "sii", siiprobe, siistart, 0, 3752130Smckusick }; 3852130Smckusick 3952130Smckusick typedef struct scsi_state { 4052130Smckusick int statusByte; /* status byte returned during STATUS_PHASE */ 4152130Smckusick int dmaDataPhase; /* which data phase to expect */ 4252130Smckusick int dmaCurPhase; /* SCSI phase if DMA is in progress */ 4352130Smckusick int dmaPrevPhase; /* SCSI phase of DMA suspended by disconnect */ 4452130Smckusick u_short *dmaAddr[2]; /* DMA buffer memory address */ 4552130Smckusick int dmaBufIndex; /* which of the above is currently in use */ 4652130Smckusick int dmalen; /* amount to transfer in this chunk */ 4752130Smckusick int cmdlen; /* total remaining amount of cmd to transfer */ 4852130Smckusick u_char *cmd; /* current pointer within scsicmd->cmd */ 4952130Smckusick int buflen; /* total remaining amount of data to transfer */ 5052130Smckusick char *buf; /* current pointer within scsicmd->buf */ 5152130Smckusick u_short flags; /* see below */ 5252130Smckusick u_short prevComm; /* command reg before disconnect */ 5352130Smckusick u_short dmaCtrl; /* DMA control register if disconnect */ 5452130Smckusick u_short dmaAddrL; /* DMA address register if disconnect */ 5552130Smckusick u_short dmaAddrH; /* DMA address register if disconnect */ 5652130Smckusick u_short dmaCnt; /* DMA count if disconnect */ 5752130Smckusick u_short dmaByte; /* DMA byte if disconnect on odd boundary */ 5852130Smckusick u_short dmaReqAck; /* DMA synchronous xfer offset or 0 if async */ 5952130Smckusick } State; 6052130Smckusick 6152130Smckusick /* state flags */ 6252130Smckusick #define FIRST_DMA 0x01 /* true if no data DMA started yet */ 6352130Smckusick 6452130Smckusick #define SII_NCMD 7 6552130Smckusick struct siisoftc { 6652130Smckusick SIIRegs *sc_regs; /* HW address of SII controller chip */ 6752130Smckusick int sc_flags; 6852130Smckusick int sc_target; /* target SCSI ID if connected */ 6952130Smckusick ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */ 7052130Smckusick State sc_st[SII_NCMD]; /* state info for each active command */ 7152130Smckusick } sii_softc[NSII]; 7252130Smckusick 7352130Smckusick /* 7452130Smckusick * MACROS for timing out spin loops. 7552130Smckusick * 7652130Smckusick * Wait until expression is true. 7752130Smckusick * 7852130Smckusick * Control register bits can change at any time so when the CPU 7952130Smckusick * reads a register, the bits might change and 8052130Smckusick * invalidate the setup and hold times for the CPU. 8152130Smckusick * This macro reads the register twice to be sure the value is stable. 8252130Smckusick * 8352130Smckusick * args: var - variable to save control register contents 8452130Smckusick * reg - control register to read 8552130Smckusick * expr - expression to spin on 8652130Smckusick * spincount - maximum number of times through the loop 8752130Smckusick * cntr - variable for number of tries 8852130Smckusick */ 8952130Smckusick #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \ 9052130Smckusick register unsigned tmp = reg; \ 9152130Smckusick for (cntr = 0; cntr < spincount; cntr++) { \ 9252130Smckusick while (tmp != (var = reg)) \ 9352130Smckusick tmp = var; \ 9452130Smckusick if (expr) \ 9552130Smckusick break; \ 9652130Smckusick if (cntr >= 100) \ 9752130Smckusick DELAY(100); \ 9852130Smckusick } \ 9952130Smckusick } 10052130Smckusick 10152130Smckusick #ifdef DEBUG 10252130Smckusick int sii_debug = 1; 10352130Smckusick int sii_debug_cmd; 10452130Smckusick int sii_debug_bn; 10552130Smckusick int sii_debug_sz; 10652130Smckusick #define NLOG 16 10752130Smckusick struct sii_log { 10852130Smckusick u_short cstat; 10952130Smckusick u_short dstat; 11052130Smckusick u_short comm; 11152130Smckusick u_short msg; 11252130Smckusick int target; 11352130Smckusick } sii_log[NLOG], *sii_logp = sii_log; 11452130Smckusick #endif 11552130Smckusick 11652130Smckusick u_char sii_buf[256]; /* used for extended messages */ 11752130Smckusick 11852130Smckusick #define NORESET 0 11952130Smckusick #define RESET 1 12052130Smckusick #define NOWAIT 0 12152130Smckusick #define WAIT 1 12252130Smckusick 12352130Smckusick /* define a safe address in the SCSI buffer for doing status & message DMA */ 12452130Smckusick #define SII_BUF_ADDR (MACH_SCSI_BUFFER_ADDR + SII_MAX_DMA_XFER_LENGTH * 14) 12552130Smckusick 12652130Smckusick extern void sii_Reset(); 12752130Smckusick extern void sii_StartCmd(); 12852130Smckusick extern void sii_CmdDone(); 12952130Smckusick extern void sii_DoIntr(); 13052130Smckusick extern void sii_StateChg(); 13152130Smckusick extern void sii_DoSync(); 13252130Smckusick extern void sii_StartDMA(); 13352130Smckusick 13452130Smckusick /* 13552130Smckusick * Test to see if device is present. 13652130Smckusick * Return true if found and initialized ok. 13752130Smckusick */ 13852130Smckusick siiprobe(cp) 13952130Smckusick register struct pmax_ctlr *cp; 14052130Smckusick { 14152130Smckusick register struct siisoftc *sc; 14252130Smckusick register int i; 14352130Smckusick 14452130Smckusick if (cp->pmax_unit >= NSII) 14552130Smckusick return (0); 14652130Smckusick sc = &sii_softc[cp->pmax_unit]; 14752130Smckusick sc->sc_regs = (SIIRegs *)cp->pmax_addr; 14852130Smckusick sc->sc_flags = cp->pmax_flags; 14952130Smckusick sc->sc_target = -1; /* no command active */ 15052130Smckusick /* 15152130Smckusick * Give each target its own DMA buffer region. 15252130Smckusick * Make it big enough for 2 max transfers so we can ping pong buffers 15352130Smckusick * while we copy the data. 15452130Smckusick */ 15552130Smckusick for (i = 0; i < SII_NCMD; i++) { 15652130Smckusick sc->sc_st[i].dmaAddr[0] = (u_short *)MACH_SCSI_BUFFER_ADDR + 15752130Smckusick 2 * SII_MAX_DMA_XFER_LENGTH * i; 15852130Smckusick sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] + 15952130Smckusick SII_MAX_DMA_XFER_LENGTH; 16052130Smckusick } 16152130Smckusick 16252130Smckusick printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr); 16352130Smckusick sii_Reset(sc->sc_regs, RESET); 16452130Smckusick return (1); 16552130Smckusick } 16652130Smckusick 16752130Smckusick /* 16852130Smckusick * Start activity on a SCSI device. 16952130Smckusick * We maintain information on each device separately since devices can 17052130Smckusick * connect/disconnect during an operation. 17152130Smckusick */ 17252130Smckusick void 17352130Smckusick siistart(scsicmd) 17452130Smckusick register ScsiCmd *scsicmd; /* command to start */ 17552130Smckusick { 17652130Smckusick register struct scsi_device *sdp = scsicmd->sd; 17752130Smckusick register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr]; 17852130Smckusick int s; 17952130Smckusick 18052130Smckusick s = splbio(); 18152130Smckusick /* 18252130Smckusick * Check if another command is already in progress. 18352130Smckusick * We may have to change this if we allow SCSI devices with 18452130Smckusick * separate LUNs. 18552130Smckusick */ 18652130Smckusick if (sc->sc_cmd[sdp->sd_drive]) { 18752130Smckusick printf("sii%d: device %s busy at start\n", sdp->sd_ctlr, 18852130Smckusick sdp->sd_driver->d_name); 18952130Smckusick (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 19052130Smckusick scsicmd->buflen, 0); 19152130Smckusick splx(s); 19252130Smckusick } 19352130Smckusick sc->sc_cmd[sdp->sd_drive] = scsicmd; 19452130Smckusick sii_StartCmd(sc, sdp->sd_drive); 19552130Smckusick splx(s); 19652130Smckusick } 19752130Smckusick 19852130Smckusick /* 19952130Smckusick * Check to see if any SII chips have pending interrupts 20052130Smckusick * and process as appropriate. 20152130Smckusick */ 20252130Smckusick void 20352697Sralph siiintr(unit) 20452697Sralph int unit; 20552130Smckusick { 20652697Sralph register struct siisoftc *sc = &sii_softc[unit]; 20752130Smckusick unsigned dstat; 20852130Smckusick 20952130Smckusick /* 21052130Smckusick * Find which controller caused the interrupt. 21152130Smckusick */ 21252697Sralph dstat = sc->sc_regs->dstat; 21352697Sralph if (dstat & (SII_CI | SII_DI)) 21452697Sralph sii_DoIntr(sc, dstat); 21552130Smckusick } 21652130Smckusick 21752130Smckusick /* 21852130Smckusick * Reset the SII chip and do a SCSI reset if 'reset' is true. 21952130Smckusick * NOTE: if !cold && reset, should probably probe for devices 22052130Smckusick * since a SCSI bus reset will set UNIT_ATTENTION. 22152130Smckusick */ 22252130Smckusick static void 22352130Smckusick sii_Reset(regs, reset) 22452130Smckusick register SIIRegs *regs; 22552130Smckusick int reset; /* TRUE => reset SCSI bus */ 22652130Smckusick { 22752130Smckusick 22852130Smckusick #ifdef DEBUG 22952130Smckusick if (sii_debug > 1) 23052130Smckusick printf("sii: RESET\n"); 23152130Smckusick #endif 23252130Smckusick /* 23352130Smckusick * Reset the SII chip. 23452130Smckusick */ 23552130Smckusick regs->comm = SII_CHRESET; 23652130Smckusick /* 23752130Smckusick * Set arbitrated bus mode. 23852130Smckusick */ 23952130Smckusick regs->csr = SII_HPM; 24052130Smckusick /* 24152130Smckusick * SII is always ID 7. 24252130Smckusick */ 24352130Smckusick regs->id = SII_ID_IO | 7; 24452130Smckusick /* 24552130Smckusick * Enable SII to drive the SCSI bus. 24652130Smckusick */ 24752130Smckusick regs->dictrl = SII_PRE; 24852130Smckusick regs->dmctrl = 0; 24952130Smckusick 25052130Smckusick if (reset) { 25152130Smckusick register int i; 25252130Smckusick 25352130Smckusick /* 25452130Smckusick * Assert SCSI bus reset for at least 25 Usec to clear the 25552130Smckusick * world. SII_DO_RST is self clearing. 25652130Smckusick * Delay 250 ms before doing any commands. 25752130Smckusick */ 25852130Smckusick regs->comm = SII_DO_RST; 25952130Smckusick MachEmptyWriteBuffer(); 26052130Smckusick DELAY(250000); 26152130Smckusick 26252130Smckusick /* rearbitrate synchronous offset */ 26352130Smckusick for (i = 0; i < SII_NCMD; i++) 26452130Smckusick sii_softc[0].sc_st[i].dmaReqAck = 0; 26552130Smckusick } 26652130Smckusick 26752130Smckusick /* 26852130Smckusick * Clear any pending interrupts from the reset. 26952130Smckusick */ 27052130Smckusick regs->cstat = regs->cstat; 27152130Smckusick regs->dstat = regs->dstat; 27252130Smckusick /* 27352130Smckusick * Set up SII for arbitrated bus mode, SCSI parity checking, 27452130Smckusick * Reselect Enable, and Interrupt Enable. 27552130Smckusick */ 27652130Smckusick regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE; 27752130Smckusick MachEmptyWriteBuffer(); 27852130Smckusick } 27952130Smckusick 28052130Smckusick /* 28152130Smckusick * Start a SCSI command by sending the cmd data 28252130Smckusick * to a SCSI controller via the SII. 28352130Smckusick * Call the device done proceedure if it can't be started. 28452130Smckusick * NOTE: we should be called with interrupts disabled. 28552130Smckusick */ 28652130Smckusick static void 28752130Smckusick sii_StartCmd(sc, target) 28852130Smckusick register struct siisoftc *sc; /* which SII to use */ 28952130Smckusick register int target; /* which command to start */ 29052130Smckusick { 29152130Smckusick register SIIRegs *regs; 29252130Smckusick register ScsiCmd *scsicmd; 29352130Smckusick register State *state; 29452130Smckusick register unsigned status; 29552130Smckusick int error, retval; 29652130Smckusick 29752130Smckusick /* if another command is currently in progress, just wait */ 29852130Smckusick if (sc->sc_target >= 0) 29952130Smckusick return; 30052130Smckusick 30152130Smckusick /* initialize state information for this command */ 30252130Smckusick scsicmd = sc->sc_cmd[target]; 30352130Smckusick state = &sc->sc_st[target]; 30452130Smckusick state->flags = FIRST_DMA; 30552130Smckusick state->prevComm = 0; 30652130Smckusick state->dmalen = 0; 30752130Smckusick state->dmaCurPhase = -1; 30852130Smckusick state->dmaPrevPhase = -1; 30952130Smckusick state->dmaBufIndex = 0; 31052130Smckusick state->cmd = scsicmd->cmd; 31152130Smckusick state->cmdlen = scsicmd->cmdlen; 31252130Smckusick if ((state->buflen = scsicmd->buflen) == 0) { 31352130Smckusick state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */ 31452130Smckusick state->buf = (char *)0; 31552130Smckusick } else { 31652130Smckusick state->dmaDataPhase = 31752130Smckusick (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ? 31852130Smckusick SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE; 31952130Smckusick state->buf = scsicmd->buf; 32052130Smckusick } 32152130Smckusick 32252130Smckusick #ifdef DEBUG 32352130Smckusick if (sii_debug > 1) { 32452130Smckusick printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 32552130Smckusick scsicmd->sd->sd_driver->d_name, target, 32652130Smckusick scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 32752130Smckusick state->dmaDataPhase); 32852130Smckusick } 32952130Smckusick sii_debug_cmd = scsicmd->cmd[0]; 33052130Smckusick if (scsicmd->cmd[0] == SCSI_READ_EXT) { 33152130Smckusick sii_debug_bn = (scsicmd->cmd[2] << 24) | 33252130Smckusick (scsicmd->cmd[3] << 16) | 33352130Smckusick (scsicmd->cmd[4] << 8) | 33452130Smckusick scsicmd->cmd[5]; 33552130Smckusick sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 33652130Smckusick } 33752130Smckusick #endif 33852130Smckusick 33952130Smckusick /* try to select the target */ 34052130Smckusick regs = sc->sc_regs; 34152130Smckusick 34252130Smckusick /* 34352130Smckusick * Another device may have selected us; in which case, 34452130Smckusick * this command will be restarted later. 34552130Smckusick */ 34652130Smckusick if ((status = regs->dstat) & (SII_CI | SII_DI)) { 34752130Smckusick sii_DoIntr(sc, status); 34852130Smckusick return; 34952130Smckusick } 35052130Smckusick 35152130Smckusick sc->sc_target = target; 35252130Smckusick if (scsicmd->flags & SCSICMD_USE_SYNC) { 35352130Smckusick printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 35452130Smckusick /* 35552130Smckusick * Setup to send both the identify message and the synchronous 35652130Smckusick * data transfer request. 35752130Smckusick */ 35852130Smckusick sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 35952130Smckusick sii_buf[1] = SCSI_EXTENDED_MSG; 36052130Smckusick sii_buf[2] = 3; /* message length */ 36152130Smckusick sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 36252130Smckusick sii_buf[4] = 0; 36352130Smckusick sii_buf[5] = 3; /* maximum SII chip supports */ 36452130Smckusick 36552130Smckusick state->dmaCurPhase = SII_MSG_OUT_PHASE, 36652130Smckusick state->dmalen = 6; 36752130Smckusick CopyToBuffer((u_short *)sii_buf, 36852130Smckusick (volatile u_short *)SII_BUF_ADDR, 6); 36952130Smckusick regs->slcsr = target; 37052130Smckusick regs->dmctrl = 0; 37152130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 37252130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 37352130Smckusick regs->dmlotc = 6; 37452130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 37552130Smckusick SII_CON | SII_MSG_OUT_PHASE; 37652130Smckusick } else { 37752130Smckusick /* do a chained, select with ATN and programmed I/O command */ 37852130Smckusick regs->data = SCSI_DIS_REC_IDENTIFY; 37952130Smckusick regs->slcsr = target; 38052130Smckusick regs->dmctrl = 0; 38152130Smckusick regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 38252130Smckusick SII_MSG_OUT_PHASE; 38352130Smckusick } 38452130Smckusick MachEmptyWriteBuffer(); 38552130Smckusick 38652130Smckusick /* 38752130Smckusick * Wait for something to happen 38852130Smckusick * (should happen soon or we would use interrupts). 38952130Smckusick */ 39052130Smckusick SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 39153085Sralph SII_WAIT_COUNT/4, retval); 39252130Smckusick 39352130Smckusick /* check to see if we are connected OK */ 39452130Smckusick if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 39552130Smckusick (SII_SCH | SII_CON)) { 39652130Smckusick regs->cstat = status; 39752130Smckusick MachEmptyWriteBuffer(); 39852130Smckusick 39952130Smckusick #ifdef DEBUG 40052130Smckusick sii_logp->target = target; 40152130Smckusick sii_logp->cstat = status; 40252130Smckusick sii_logp->dstat = 0; 40352130Smckusick sii_logp->comm = regs->comm; 40452130Smckusick sii_logp->msg = -1; 40552130Smckusick if (++sii_logp >= &sii_log[NLOG]) 40652130Smckusick sii_logp = sii_log; 40752130Smckusick #endif 40852130Smckusick 40952130Smckusick /* wait a short time for command phase */ 41052130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 41152130Smckusick SII_WAIT_COUNT, retval); 41252130Smckusick #ifdef DEBUG 41352130Smckusick if (sii_debug > 2) 41452130Smckusick printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 41552130Smckusick #endif 41652130Smckusick if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 41752130Smckusick (SII_MIS | SII_CMD_PHASE)) { 41852130Smckusick printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 41952130Smckusick regs->cstat, status, retval); /* XXX */ 42052130Smckusick /* process interrupt or continue until it happens */ 42152130Smckusick if (status & (SII_CI | SII_DI)) 42252130Smckusick sii_DoIntr(sc, status); 42352130Smckusick return; 42452130Smckusick } 42552130Smckusick regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 42652130Smckusick 42752130Smckusick /* send command data */ 42852130Smckusick CopyToBuffer((u_short *)state->cmd, 42952130Smckusick (volatile u_short *)state->dmaAddr[0], state->cmdlen); 43052130Smckusick sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 43152130Smckusick state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 43252130Smckusick 43352130Smckusick /* wait a little while for DMA to finish */ 43452130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 43552130Smckusick SII_WAIT_COUNT, retval); 43652130Smckusick #ifdef DEBUG 43752130Smckusick if (sii_debug > 2) 43852130Smckusick printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 43952130Smckusick #endif 44052130Smckusick if (status & (SII_CI | SII_DI)) 44152130Smckusick sii_DoIntr(sc, status); 44252130Smckusick #ifdef DEBUG 44352130Smckusick if (sii_debug > 2) 44452130Smckusick printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 44552130Smckusick #endif 44652130Smckusick return; 44752130Smckusick } 44852130Smckusick 44952130Smckusick /* 45052130Smckusick * Another device may have selected us; in which case, 45152130Smckusick * this command will be restarted later. 45252130Smckusick */ 45352130Smckusick if (status & (SII_CI | SII_DI)) { 45452130Smckusick sii_DoIntr(sc, regs->dstat); 45552130Smckusick return; 45652130Smckusick } 45752130Smckusick 45852130Smckusick /* 45952130Smckusick * Disconnect if selection command still in progress. 46052130Smckusick */ 46152130Smckusick if (status & SII_SIP) { 46252130Smckusick error = ENXIO; /* device didn't respond */ 46352130Smckusick regs->comm = SII_DISCON; 46452130Smckusick MachEmptyWriteBuffer(); 46552130Smckusick SII_WAIT_UNTIL(status, regs->cstat, 46652130Smckusick !(status & (SII_CON | SII_SIP)), 46752130Smckusick SII_WAIT_COUNT, retval); 46852130Smckusick } else 46952130Smckusick error = EBUSY; /* couldn't get the bus */ 47052130Smckusick #ifdef DEBUG 47153085Sralph if (sii_debug > 1) 47252130Smckusick printf("sii_StartCmd: Couldn't select target %d error %d\n", 47352130Smckusick target, error); 47452130Smckusick #endif 47552130Smckusick sc->sc_target = -1; 47652130Smckusick regs->cstat = 0xffff; 47752130Smckusick regs->dstat = 0xffff; 47852130Smckusick regs->comm = 0; 47952130Smckusick MachEmptyWriteBuffer(); 48052130Smckusick sii_CmdDone(sc, target, error); 48152130Smckusick } 48252130Smckusick 48352130Smckusick /* 48452130Smckusick * Process interrupt conditions. 48552130Smckusick */ 48652130Smckusick static void 48752130Smckusick sii_DoIntr(sc, dstat) 48852130Smckusick register struct siisoftc *sc; 48952130Smckusick register unsigned dstat; 49052130Smckusick { 49152130Smckusick register SIIRegs *regs = sc->sc_regs; 49252130Smckusick register State *state; 49352130Smckusick register unsigned cstat; 49452130Smckusick register int i; 49552130Smckusick unsigned comm, msg; 49652130Smckusick 49752130Smckusick again: 49852130Smckusick comm = regs->comm; 49952130Smckusick 50052130Smckusick #ifdef DEBUG 50152130Smckusick if (sii_debug > 3) 50252130Smckusick printf("sii_DoIntr: cs %x, ds %x cm %x ", 50352130Smckusick regs->cstat, dstat, comm); 50452130Smckusick sii_logp->target = sc->sc_target; 50552130Smckusick sii_logp->cstat = regs->cstat; 50652130Smckusick sii_logp->dstat = dstat; 50752130Smckusick sii_logp->comm = comm; 50852130Smckusick sii_logp->msg = -1; 50952130Smckusick if (++sii_logp >= &sii_log[NLOG]) 51052130Smckusick sii_logp = sii_log; 51152130Smckusick #endif 51252130Smckusick 51352130Smckusick regs->dstat = dstat; /* acknowledge everything */ 51452130Smckusick MachEmptyWriteBuffer(); 51552130Smckusick 51652130Smckusick if (dstat & SII_CI) { 51752130Smckusick /* deglitch cstat register */ 51852130Smckusick msg = regs->cstat; 51952130Smckusick while (msg != (cstat = regs->cstat)) 52052130Smckusick msg = cstat; 52152130Smckusick regs->cstat = cstat; /* acknowledge everything */ 52252130Smckusick MachEmptyWriteBuffer(); 52352130Smckusick #ifdef DEBUG 52452130Smckusick if (sii_logp > sii_log) 52552130Smckusick sii_logp[-1].cstat = cstat; 52652130Smckusick else 52752130Smckusick sii_log[NLOG - 1].cstat = cstat; 52852130Smckusick #endif 52952130Smckusick 53052130Smckusick /* check for a BUS RESET */ 53152130Smckusick if (cstat & SII_RST) { 53252130Smckusick printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 53352130Smckusick /* need to flush disconnected commands */ 53452697Sralph for (i = 0; i < SII_NCMD; i++) { 53552697Sralph if (!sc->sc_cmd[i]) 53652697Sralph continue; 53752130Smckusick sii_CmdDone(sc, i, EIO); 53852697Sralph } 53952130Smckusick /* rearbitrate synchronous offset */ 54052130Smckusick for (i = 0; i < SII_NCMD; i++) 54152130Smckusick sc->sc_st[i].dmaReqAck = 0; 54252130Smckusick sc->sc_target = -1; 54352130Smckusick return; 54452130Smckusick } 54552130Smckusick 54652130Smckusick #ifdef notdef 54752130Smckusick /* 54852130Smckusick * Check for a BUS ERROR. 54952130Smckusick * According to DEC, this feature doesn't really work 55052130Smckusick * and to just clear the bit if it's set. 55152130Smckusick */ 55252130Smckusick if (cstat & SII_BER) { 55352130Smckusick } 55452130Smckusick #endif 55552130Smckusick 55652130Smckusick /* check for state change */ 55752130Smckusick if (cstat & SII_SCH) { 55852130Smckusick sii_StateChg(sc, cstat); 55952130Smckusick comm = regs->comm; 56052130Smckusick } 56152130Smckusick } 56252130Smckusick 56352130Smckusick /* check for DMA completion */ 56452130Smckusick if (dstat & SII_DNE) { 56552130Smckusick u_short *dma; 56652130Smckusick char *buf; 56752130Smckusick 56852130Smckusick /* check for a PARITY ERROR */ 56952130Smckusick if (dstat & SII_IPE) { 57052130Smckusick printf("sii%d: Parity error!!\n", sc - sii_softc); 57152130Smckusick goto abort; 57252130Smckusick } 57352130Smckusick /* 57452130Smckusick * There is a race condition with SII_SCH. There is a short 57552130Smckusick * window between the time a SII_SCH is seen after a disconnect 57652130Smckusick * and when the SII_SCH is cleared. A reselect can happen 57752130Smckusick * in this window and we will clear the SII_SCH without 57852130Smckusick * processing the reconnect. 57952130Smckusick */ 58052130Smckusick if (sc->sc_target < 0) { 58152130Smckusick cstat = regs->cstat; 58252130Smckusick printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 58352130Smckusick sc - sii_softc, sc->sc_target, 58452130Smckusick regs->slcsr, regs->destat, 58552130Smckusick cstat); /* XXX */ 58652130Smckusick if (cstat & SII_DST) { 58752130Smckusick sc->sc_target = regs->destat; 58852130Smckusick state->prevComm = 0; 58952130Smckusick } else 59052130Smckusick panic("sc_target 1"); 59152130Smckusick } 59252130Smckusick state = &sc->sc_st[sc->sc_target]; 59352130Smckusick /* dmalen = amount left to transfer, i = amount transfered */ 59452130Smckusick i = state->dmalen; 59552130Smckusick state->dmalen = 0; 59652130Smckusick state->dmaCurPhase = -1; 59752130Smckusick #ifdef DEBUG 59852130Smckusick if (sii_debug > 4) { 59952130Smckusick printf("DNE: amt %d ", i); 60052130Smckusick if (!(dstat & SII_TCZ)) 60152130Smckusick printf("no TCZ?? (%d) ", regs->dmlotc); 60252130Smckusick } else if (!(dstat & SII_TCZ)) { 60352130Smckusick printf("sii%d: device %d: no TCZ?? (%d)\n", 60452130Smckusick sc - sii_softc, sc->sc_target, regs->dmlotc); 60552130Smckusick sii_DumpLog(); /* XXX */ 60652130Smckusick } 60752130Smckusick #endif 60852130Smckusick switch (comm & SII_PHASE_MSK) { 60952130Smckusick case SII_CMD_PHASE: 61052130Smckusick state->cmdlen -= i; 61152130Smckusick break; 61252130Smckusick 61352130Smckusick case SII_DATA_IN_PHASE: 61452130Smckusick /* check for more data for the same phase */ 61552130Smckusick dma = state->dmaAddr[state->dmaBufIndex]; 61652130Smckusick buf = state->buf; 61752130Smckusick state->buf += i; 61852130Smckusick state->buflen -= i; 61952130Smckusick if (state->buflen > 0 && !(dstat & SII_MIS)) { 62052130Smckusick int len; 62152130Smckusick 62252130Smckusick /* start reading next chunk */ 62352130Smckusick len = state->buflen; 62452130Smckusick if (len > SII_MAX_DMA_XFER_LENGTH) 62552130Smckusick len = SII_MAX_DMA_XFER_LENGTH; 62652130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 62752130Smckusick sii_StartDMA(regs, 62852130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 62952130Smckusick state->dmaAddr[state->dmaBufIndex], 63052130Smckusick state->dmalen = len); 63152130Smckusick dstat &= ~(SII_IBF | SII_TBE); 63252130Smckusick } 63352130Smckusick /* copy in the data */ 63452130Smckusick CopyFromBuffer((volatile u_short *)dma, buf, i); 63552130Smckusick break; 63652130Smckusick 63752130Smckusick case SII_DATA_OUT_PHASE: 63852130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 63952130Smckusick state->buf += i; 64052130Smckusick state->buflen -= i; 64152130Smckusick 64252130Smckusick /* check for more data for the same phase */ 64352130Smckusick if (state->buflen <= 0 || (dstat & SII_MIS)) 64452130Smckusick break; 64552130Smckusick 64652130Smckusick /* start next chunk */ 64752130Smckusick i = state->buflen; 64852130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) { 64952130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 65052130Smckusick SII_DATA_OUT_PHASE, 65152130Smckusick state->dmaAddr[state->dmaBufIndex], 65252130Smckusick state->dmalen = 65352130Smckusick SII_MAX_DMA_XFER_LENGTH); 65452130Smckusick /* prepare for next chunk */ 65552130Smckusick i -= SII_MAX_DMA_XFER_LENGTH; 65652130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 65752130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 65852130Smckusick CopyToBuffer((u_short *)(state->buf + 65952130Smckusick SII_MAX_DMA_XFER_LENGTH), 66052130Smckusick (volatile u_short *) 66152130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 66252130Smckusick } else { 66352130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 66452130Smckusick SII_DATA_OUT_PHASE, 66552130Smckusick state->dmaAddr[state->dmaBufIndex], 66652130Smckusick state->dmalen = i); 66752130Smckusick } 66852130Smckusick dstat &= ~(SII_IBF | SII_TBE); 66952130Smckusick break; 67052130Smckusick 67152130Smckusick default: 67252130Smckusick printf("sii%d: device %d: unexpected DNE\n", 67352130Smckusick sc - sii_softc, sc->sc_target); 67452130Smckusick #ifdef DEBUG 67552130Smckusick sii_DumpLog(); 67652130Smckusick #endif 67752130Smckusick } 67852130Smckusick } 67952130Smckusick 68052130Smckusick /* check for phase change or another MsgIn/Out */ 68152130Smckusick if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 68252130Smckusick /* 68352130Smckusick * There is a race condition with SII_SCH. There is a short 68452130Smckusick * window between the time a SII_SCH is seen after a disconnect 68552130Smckusick * and when the SII_SCH is cleared. A reselect can happen 68652130Smckusick * in this window and we will clear the SII_SCH without 68752130Smckusick * processing the reconnect. 68852130Smckusick */ 68952130Smckusick if (sc->sc_target < 0) { 69052130Smckusick cstat = regs->cstat; 69152130Smckusick printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 69252130Smckusick sc - sii_softc, sc->sc_target, 69352130Smckusick regs->slcsr, regs->destat, 69452130Smckusick cstat, dstat); /* XXX */ 69552130Smckusick if (cstat & SII_DST) { 69652130Smckusick sc->sc_target = regs->destat; 69752130Smckusick state->prevComm = 0; 69852130Smckusick } else 69952130Smckusick panic("sc_target 2"); 70052130Smckusick } 70152130Smckusick state = &sc->sc_st[sc->sc_target]; 70252130Smckusick switch (dstat & SII_PHASE_MSK) { 70352130Smckusick case SII_CMD_PHASE: 70452130Smckusick if (state->dmaPrevPhase >= 0) { 70552130Smckusick /* restart DMA after disconnect/reconnect */ 70652130Smckusick if (state->dmaPrevPhase != SII_CMD_PHASE) { 70752130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 70852130Smckusick sc - sii_softc, sc->sc_target); 70952130Smckusick goto abort; 71052130Smckusick } 71152130Smckusick state->dmaCurPhase = SII_CMD_PHASE; 71252130Smckusick state->dmaPrevPhase = -1; 71352130Smckusick regs->dmaddrl = state->dmaAddrL; 71452130Smckusick regs->dmaddrh = state->dmaAddrH; 71552130Smckusick regs->dmlotc = state->dmaCnt; 71652130Smckusick if (state->dmaCnt & 1) 71752130Smckusick regs->dmabyte = state->dmaByte; 71852130Smckusick regs->comm = SII_DMA | SII_INXFER | 71952130Smckusick (comm & SII_STATE_MSK) | SII_CMD_PHASE; 72052130Smckusick MachEmptyWriteBuffer(); 72152130Smckusick #ifdef DEBUG 72252130Smckusick if (sii_debug > 4) 72352130Smckusick printf("Cmd dcnt %d dadr %x ", 72452130Smckusick state->dmaCnt, 72552130Smckusick (state->dmaAddrH << 16) | 72652130Smckusick state->dmaAddrL); 72752130Smckusick #endif 72852130Smckusick } else { 72952130Smckusick /* send command data */ 73052130Smckusick i = state->cmdlen; 73152130Smckusick if (i == 0) { 73252130Smckusick printf("sii%d: device %d: cmd count exceeded\n", 73352130Smckusick sc - sii_softc, sc->sc_target); 73452130Smckusick goto abort; 73552130Smckusick } 73652130Smckusick CopyToBuffer((u_short *)state->cmd, 73752130Smckusick (volatile u_short *)state->dmaAddr[0], 73852130Smckusick i); 73952130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 74052130Smckusick SII_CMD_PHASE, state->dmaAddr[0], 74152130Smckusick state->dmalen = i); 74252130Smckusick } 74352130Smckusick /* wait a short time for XFER complete */ 74452130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 74552130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 74652130Smckusick if (dstat & (SII_CI | SII_DI)) { 74752130Smckusick #ifdef DEBUG 74852130Smckusick if (sii_debug > 4) 74952130Smckusick printf("cnt %d\n", i); 75052130Smckusick else if (sii_debug > 0) 75152130Smckusick printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 75252130Smckusick dstat, i); 75352130Smckusick #endif 75452130Smckusick goto again; 75552130Smckusick } 75652130Smckusick break; 75752130Smckusick 75852130Smckusick case SII_DATA_IN_PHASE: 75952130Smckusick case SII_DATA_OUT_PHASE: 76052130Smckusick regs->dmctrl = state->dmaReqAck; 76152130Smckusick if (state->cmdlen > 0) { 76252130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 76352130Smckusick sc - sii_softc, sc->sc_target, 76452130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 76552130Smckusick state->cmdlen); 76652130Smckusick state->cmdlen = 0; 76752130Smckusick #ifdef DEBUG 76852130Smckusick sii_DumpLog(); 76952130Smckusick #endif 77052130Smckusick } 77152130Smckusick if (state->dmaPrevPhase >= 0) { 77252130Smckusick /* restart DMA after disconnect/reconnect */ 77352130Smckusick if (state->dmaPrevPhase != 77452130Smckusick (dstat & SII_PHASE_MSK)) { 77552130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 77652130Smckusick sc - sii_softc, sc->sc_target); 77752130Smckusick goto abort; 77852130Smckusick } 77952130Smckusick state->dmaCurPhase = state->dmaPrevPhase; 78052130Smckusick state->dmaPrevPhase = -1; 78152130Smckusick regs->dmaddrl = state->dmaAddrL; 78252130Smckusick regs->dmaddrh = state->dmaAddrH; 78352130Smckusick regs->dmlotc = state->dmaCnt; 78452130Smckusick if (state->dmaCnt & 1) 78552130Smckusick regs->dmabyte = state->dmaByte; 78652130Smckusick regs->comm = SII_DMA | SII_INXFER | 78752130Smckusick (comm & SII_STATE_MSK) | 78852130Smckusick state->dmaCurPhase; 78952130Smckusick MachEmptyWriteBuffer(); 79052130Smckusick #ifdef DEBUG 79152130Smckusick if (sii_debug > 4) 79252130Smckusick printf("Data %d dcnt %d dadr %x ", 79352130Smckusick state->dmaDataPhase, 79452130Smckusick state->dmaCnt, 79552130Smckusick (state->dmaAddrH << 16) | 79652130Smckusick state->dmaAddrL); 79752130Smckusick #endif 79852130Smckusick break; 79952130Smckusick } 80052130Smckusick if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 80152130Smckusick printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 80252130Smckusick sc - sii_softc, sc->sc_target, 80352130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0]); 80452130Smckusick goto abort; 80552130Smckusick } 80652130Smckusick #ifdef DEBUG 80752130Smckusick if (sii_debug > 4) { 80852130Smckusick printf("Data %d ", state->dmaDataPhase); 80952130Smckusick if (sii_debug > 5) 81052130Smckusick printf("\n"); 81152130Smckusick } 81252130Smckusick #endif 81352130Smckusick i = state->buflen; 81452130Smckusick if (i == 0) { 81552130Smckusick printf("sii%d: device %d: data count exceeded\n", 81652130Smckusick sc - sii_softc, sc->sc_target); 81752130Smckusick goto abort; 81852130Smckusick } 81952130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 82052130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 82152130Smckusick if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 82252130Smckusick sii_StartDMA(regs, 82352130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 82452130Smckusick state->dmaAddr[state->dmaBufIndex], 82552130Smckusick state->dmalen = i); 82652130Smckusick break; 82752130Smckusick } 82852130Smckusick /* start first chunk */ 82952130Smckusick if (state->flags & FIRST_DMA) { 83052130Smckusick state->flags &= ~FIRST_DMA; 83152130Smckusick CopyToBuffer((u_short *)state->buf, 83252130Smckusick (volatile u_short *) 83352130Smckusick state->dmaAddr[state->dmaBufIndex], i); 83452130Smckusick } 83552130Smckusick sii_StartDMA(regs, 83652130Smckusick state->dmaCurPhase = SII_DATA_OUT_PHASE, 83752130Smckusick state->dmaAddr[state->dmaBufIndex], 83852130Smckusick state->dmalen = i); 83952130Smckusick i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 84052130Smckusick if (i > 0) { 84152130Smckusick /* prepare for next chunk */ 84252130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 84352130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 84452130Smckusick CopyToBuffer((u_short *)(state->buf + 84552130Smckusick SII_MAX_DMA_XFER_LENGTH), 84652130Smckusick (volatile u_short *) 84752130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 84852130Smckusick } 84952130Smckusick break; 85052130Smckusick 85152130Smckusick case SII_STATUS_PHASE: 85252130Smckusick if (state->cmdlen > 0) { 85352130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 85452130Smckusick sc - sii_softc, sc->sc_target, 85552130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 85652130Smckusick state->cmdlen); 85752130Smckusick state->cmdlen = 0; 85852130Smckusick #ifdef DEBUG 85952130Smckusick sii_DumpLog(); 86052130Smckusick #endif 86152130Smckusick } 86252130Smckusick 86352130Smckusick /* read amount transfered if DMA didn't finish */ 86452130Smckusick if (state->dmalen > 0) { 86552130Smckusick i = state->dmalen - regs->dmlotc; 86652130Smckusick state->dmalen = 0; 86752130Smckusick state->dmaCurPhase = -1; 86852130Smckusick regs->dmlotc = 0; 86952130Smckusick regs->comm = comm & 87052130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 87152130Smckusick MachEmptyWriteBuffer(); 87252130Smckusick regs->dstat = SII_DNE; 87352130Smckusick MachEmptyWriteBuffer(); 87452130Smckusick #ifdef DEBUG 87552130Smckusick if (sii_debug > 4) 87652130Smckusick printf("DMA amt %d ", i); 87752130Smckusick #endif 87852130Smckusick switch (comm & SII_PHASE_MSK) { 87952130Smckusick case SII_DATA_IN_PHASE: 88052130Smckusick /* copy in the data */ 88152130Smckusick CopyFromBuffer((volatile u_short *) 88252130Smckusick state->dmaAddr[state->dmaBufIndex], 88352130Smckusick state->buf, i); 88452130Smckusick 88552130Smckusick case SII_CMD_PHASE: 88652130Smckusick case SII_DATA_OUT_PHASE: 88752130Smckusick state->buflen -= i; 88852130Smckusick } 88952130Smckusick } 89052130Smckusick 89152130Smckusick /* read a one byte status message */ 89252130Smckusick state->statusByte = msg = 89352130Smckusick sii_GetByte(regs, SII_STATUS_PHASE); 89452130Smckusick if (msg < 0) { 89552130Smckusick dstat = regs->dstat; 89652130Smckusick goto again; 89752130Smckusick } 89852130Smckusick #ifdef DEBUG 89952130Smckusick if (sii_debug > 4) 90052130Smckusick printf("Status %x ", msg); 90152130Smckusick if (sii_logp > sii_log) 90252130Smckusick sii_logp[-1].msg = msg; 90352130Smckusick else 90452130Smckusick sii_log[NLOG - 1].msg = msg; 90552130Smckusick #endif 90652130Smckusick 90752130Smckusick /* do a quick wait for COMMAND_COMPLETE */ 90852130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 90952130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 91052130Smckusick if (dstat & (SII_CI | SII_DI)) { 91152130Smckusick #ifdef DEBUG 91252130Smckusick if (sii_debug > 4) 91352130Smckusick printf("cnt2 %d\n", i); 91452130Smckusick #endif 91552130Smckusick goto again; 91652130Smckusick } 91752130Smckusick break; 91852130Smckusick 91952130Smckusick case SII_MSG_IN_PHASE: 92052130Smckusick /* 92152130Smckusick * Save DMA state if DMA didn't finish. 92252130Smckusick * Be careful not to save state again after reconnect 92352130Smckusick * and see RESTORE_POINTER message. 92452130Smckusick * Note that the SII DMA address is not incremented 92552130Smckusick * as DMA proceeds. 92652130Smckusick */ 92752130Smckusick if (state->dmaCurPhase > 0) { 92852130Smckusick /* save dma registers */ 92952130Smckusick state->dmaPrevPhase = state->dmaCurPhase; 93052130Smckusick state->dmaCurPhase = -1; 93152130Smckusick state->dmaCnt = i = regs->dmlotc; 93252130Smckusick if (dstat & SII_OBB) 93352130Smckusick state->dmaByte = regs->dmabyte; 93452130Smckusick if (i == 0) 93552130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 93652130Smckusick i = state->dmalen - i; 93752130Smckusick /* note: no carry from dmaddrl to dmaddrh */ 93852130Smckusick state->dmaAddrL = regs->dmaddrl + i; 93952130Smckusick state->dmaAddrH = regs->dmaddrh; 94052130Smckusick regs->comm = comm & 94152130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 94252130Smckusick MachEmptyWriteBuffer(); 94352130Smckusick regs->dstat = SII_DNE; 94452130Smckusick MachEmptyWriteBuffer(); 94552130Smckusick #ifdef DEBUG 94652130Smckusick if (sii_debug > 4) { 94752130Smckusick printf("SavP dcnt %d dadr %x ", 94852130Smckusick state->dmaCnt, 94952130Smckusick (state->dmaAddrH << 16) | 95052130Smckusick state->dmaAddrL); 95152130Smckusick if (((dstat & SII_OBB) != 0) ^ 95252130Smckusick (state->dmaCnt & 1)) 95352130Smckusick printf("OBB??? "); 95452130Smckusick } else if (sii_debug > 0) { 95552130Smckusick if (((dstat & SII_OBB) != 0) ^ 95652130Smckusick (state->dmaCnt & 1)) { 95752130Smckusick printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 95852130Smckusick dstat, state->dmaCnt); 95952130Smckusick sii_DumpLog(); 96052130Smckusick } 96152130Smckusick } 96252130Smckusick #endif 96352130Smckusick } 96452130Smckusick 96552130Smckusick /* read a one byte message */ 96652130Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 96752130Smckusick if (msg < 0) { 96852130Smckusick dstat = regs->dstat; 96952130Smckusick goto again; 97052130Smckusick } 97152130Smckusick #ifdef DEBUG 97252130Smckusick if (sii_debug > 4) 97352130Smckusick printf("MsgIn %x ", msg); 97452130Smckusick if (sii_logp > sii_log) 97552130Smckusick sii_logp[-1].msg = msg; 97652130Smckusick else 97752130Smckusick sii_log[NLOG - 1].msg = msg; 97852130Smckusick #endif 97952130Smckusick 98052130Smckusick /* process message */ 98152130Smckusick switch (msg) { 98252130Smckusick case SCSI_COMMAND_COMPLETE: 98352130Smckusick msg = sc->sc_target; 98452130Smckusick sc->sc_target = -1; 98552130Smckusick /* 98652130Smckusick * Wait a short time for disconnect. 98752130Smckusick * Don't be fooled if SII_BER happens first. 98852130Smckusick * Note: a reselect may happen here. 98952130Smckusick */ 99052130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 99152130Smckusick cstat & (SII_RST | SII_SCH), 99252130Smckusick SII_WAIT_COUNT, i); 99352130Smckusick if ((cstat & (SII_RST | SII_SCH | 99452130Smckusick SII_STATE_MSK)) == SII_SCH) { 99552130Smckusick regs->cstat = SII_SCH | SII_BER; 99652130Smckusick regs->comm = 0; 99752130Smckusick MachEmptyWriteBuffer(); 99852130Smckusick /* 99952130Smckusick * Double check that we didn't miss a 100052130Smckusick * state change between seeing it and 100152130Smckusick * clearing the SII_SCH bit. 100252130Smckusick */ 100352130Smckusick i = regs->cstat; 100452130Smckusick if (!(i & SII_SCH) && 100552130Smckusick (i & SII_STATE_MSK) != 100652130Smckusick (cstat & SII_STATE_MSK)) 100752130Smckusick sii_StateChg(sc, i); 100852130Smckusick } 100952130Smckusick #ifdef DEBUG 101052130Smckusick if (sii_debug > 4) 101152130Smckusick printf("cs %x\n", cstat); 101252130Smckusick #endif 101352130Smckusick sii_CmdDone(sc, msg, 0); 101452130Smckusick break; 101552130Smckusick 101652130Smckusick case SCSI_EXTENDED_MSG: 101752130Smckusick /* read the message length */ 101852130Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 101952130Smckusick if (msg < 0) { 102052130Smckusick dstat = regs->dstat; 102152130Smckusick goto again; 102252130Smckusick } 102352130Smckusick if (msg == 0) 102452130Smckusick msg = 256; 102552130Smckusick sii_StartDMA(regs, SII_MSG_IN_PHASE, 102652130Smckusick (u_short *)SII_BUF_ADDR, msg); 102752130Smckusick /* wait a short time for XFER complete */ 102852130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 102952130Smckusick (dstat & (SII_DNE | SII_TCZ)) == 103052130Smckusick (SII_DNE | SII_TCZ), 103152130Smckusick SII_WAIT_COUNT, i); 103252130Smckusick 103352130Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != 103452130Smckusick (SII_DNE | SII_TCZ)) { 103552130Smckusick #ifdef DEBUG 103652130Smckusick if (sii_debug > 4) 103752130Smckusick printf("cnt0 %d\n", i); 103852130Smckusick else if (sii_debug > 0) 103952130Smckusick printf("sii_DoIntr: emsg in ds %x cnt %d\n", 104052130Smckusick dstat, i); 104152130Smckusick #endif 104252130Smckusick printf("sii: ds %x cm %x i %d lotc %d\n", 104352130Smckusick dstat, comm, i, regs->dmlotc); /* XXX */ 104452130Smckusick sii_DumpLog(); /* XXX */ 104552130Smckusick goto again; 104652130Smckusick } 104752130Smckusick 104852130Smckusick /* clear the DNE, other errors handled later */ 104952130Smckusick regs->dstat = SII_DNE; 105052130Smckusick MachEmptyWriteBuffer(); 105152130Smckusick 105252130Smckusick CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, 105352130Smckusick sii_buf + 2, msg); 105452130Smckusick switch (sii_buf[2]) { 105552130Smckusick case SCSI_MODIFY_DATA_PTR: 105652130Smckusick i = (sii_buf[3] << 24) | 105752130Smckusick (sii_buf[4] << 16) | 105852130Smckusick (sii_buf[5] << 8) | 105952130Smckusick sii_buf[6]; 106052130Smckusick if (state->dmaPrevPhase >= 0) { 106152130Smckusick state->dmaAddrL += i; 106252130Smckusick state->dmaCnt -= i; 106352130Smckusick } 106452130Smckusick break; 106552130Smckusick 106652130Smckusick case SCSI_SYNCHRONOUS_XFER: 106752130Smckusick sii_DoSync(regs, state); 106852130Smckusick break; 106952130Smckusick 107052130Smckusick case SCSI_EXTENDED_IDENTIFY: 107152130Smckusick case SCSI_WIDE_XFER: 107252130Smckusick default: 107352130Smckusick reject: 107452130Smckusick /* send a reject message */ 107552130Smckusick regs->data = SCSI_MESSAGE_REJECT; 107652130Smckusick regs->comm = SII_INXFER | SII_ATN | 107752130Smckusick (regs->cstat & SII_STATE_MSK) | 107852130Smckusick SII_MSG_OUT_PHASE; 107952130Smckusick MachEmptyWriteBuffer(); 108052130Smckusick /* wait for XFER complete */ 108152130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 108252130Smckusick (dstat & 108352130Smckusick (SII_DNE | SII_PHASE_MSK)) == 108452130Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 108552130Smckusick SII_WAIT_COUNT, i); 108652130Smckusick 108752130Smckusick if ((dstat & 108852130Smckusick (SII_DNE | SII_PHASE_MSK)) != 108952130Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) 109052130Smckusick break; 109152130Smckusick regs->dstat = SII_DNE; 109252130Smckusick MachEmptyWriteBuffer(); 109352130Smckusick } 109452130Smckusick break; 109552130Smckusick 109652130Smckusick case SCSI_SAVE_DATA_POINTER: 109752130Smckusick case SCSI_RESTORE_POINTERS: 109852130Smckusick /* wait a short time for another msg */ 109952130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 110052130Smckusick dstat & (SII_CI | SII_DI), 110152130Smckusick SII_WAIT_COUNT, i); 110252130Smckusick if (dstat & (SII_CI | SII_DI)) { 110352130Smckusick #ifdef DEBUG 110452130Smckusick if (sii_debug > 4) 110552130Smckusick printf("cnt %d\n", i); 110652130Smckusick #endif 110752130Smckusick goto again; 110852130Smckusick } 110952130Smckusick break; 111052130Smckusick 111152130Smckusick case SCSI_DISCONNECT: 111252130Smckusick state->prevComm = comm; 111352130Smckusick #ifdef DEBUG 111452130Smckusick if (sii_debug > 4) 111552130Smckusick printf("disconn %d ", sc->sc_target); 111652130Smckusick #endif 111752130Smckusick /* 111852130Smckusick * Wait a short time for disconnect. 111952130Smckusick * Don't be fooled if SII_BER happens first. 112052130Smckusick * Note: a reselect may happen here. 112152130Smckusick */ 112252130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 112352130Smckusick cstat & (SII_RST | SII_SCH), 112452130Smckusick SII_WAIT_COUNT, i); 112552130Smckusick if ((cstat & (SII_RST | SII_SCH | 112652130Smckusick SII_STATE_MSK)) != SII_SCH) { 112752130Smckusick #ifdef DEBUG 112852130Smckusick if (sii_debug > 4) 112952130Smckusick printf("cnt %d\n", i); 113052130Smckusick #endif 113152130Smckusick dstat = regs->dstat; 113252130Smckusick goto again; 113352130Smckusick } 113452130Smckusick regs->cstat = SII_SCH | SII_BER; 113552130Smckusick regs->comm = 0; 113652130Smckusick MachEmptyWriteBuffer(); 113752130Smckusick sc->sc_target = -1; 113852130Smckusick /* 113952130Smckusick * Double check that we didn't miss a state 114052130Smckusick * change between seeing it and clearing 114152130Smckusick * the SII_SCH bit. 114252130Smckusick */ 114352130Smckusick i = regs->cstat; 114452130Smckusick if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 114552130Smckusick (cstat & SII_STATE_MSK)) 114652130Smckusick sii_StateChg(sc, i); 114752130Smckusick break; 114852130Smckusick 114952130Smckusick case SCSI_MESSAGE_REJECT: 115052130Smckusick printf("sii%d: device %d: message reject.\n", 115152130Smckusick sc - sii_softc, sc->sc_target); 115252130Smckusick goto abort; 115352130Smckusick 115452130Smckusick default: 115552130Smckusick if (!(msg & SCSI_IDENTIFY)) { 115652130Smckusick printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", 115752130Smckusick sc - sii_softc, sc->sc_target, 115852130Smckusick msg); 115952130Smckusick #ifdef DEBUG 116052130Smckusick sii_DumpLog(); 116152130Smckusick #endif 116252130Smckusick break; 116352130Smckusick } 116452130Smckusick /* may want to check LUN some day */ 116552130Smckusick /* wait a short time for another msg */ 116652130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 116752130Smckusick dstat & (SII_CI | SII_DI), 116852130Smckusick SII_WAIT_COUNT, i); 116952130Smckusick if (dstat & (SII_CI | SII_DI)) { 117052130Smckusick #ifdef DEBUG 117152130Smckusick if (sii_debug > 4) 117252130Smckusick printf("cnt %d\n", i); 117352130Smckusick #endif 117452130Smckusick goto again; 117552130Smckusick } 117652130Smckusick } 117752130Smckusick break; 117852130Smckusick 117952130Smckusick case SII_MSG_OUT_PHASE: 118052130Smckusick #ifdef DEBUG 118152130Smckusick if (sii_debug > 4) 118252130Smckusick printf("MsgOut\n"); 118352130Smckusick #endif 118452130Smckusick 118552130Smckusick regs->data = SCSI_NO_OP; 118652130Smckusick regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 118752130Smckusick SII_MSG_OUT_PHASE; 118852130Smckusick MachEmptyWriteBuffer(); 118952130Smckusick 119052130Smckusick /* wait a short time for XFER complete */ 119152130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 119252130Smckusick SII_WAIT_COUNT, i); 119352130Smckusick #ifdef DEBUG 119452130Smckusick if (sii_debug > 4) 119552130Smckusick printf("ds %x i %d\n", dstat, i); 119652130Smckusick #endif 119752130Smckusick /* just clear the DNE bit and check errors later */ 119852130Smckusick if (dstat & SII_DNE) { 119952130Smckusick regs->dstat = SII_DNE; 120052130Smckusick MachEmptyWriteBuffer(); 120152130Smckusick } 120252130Smckusick break; 120352130Smckusick 120452130Smckusick default: 120552130Smckusick printf("sii%d: Couldn't handle phase %d... ignoring.\n", 120652130Smckusick sc - sii_softc, dstat & SII_PHASE_MSK); 120752130Smckusick } 120852130Smckusick } 120952130Smckusick 121052130Smckusick #ifdef DEBUG 121152130Smckusick if (sii_debug > 3) 121252130Smckusick printf("\n"); 121352130Smckusick #endif 121452130Smckusick /* 121552130Smckusick * Check to make sure we won't be interrupted again. 121652130Smckusick * Deglitch dstat register. 121752130Smckusick */ 121852130Smckusick msg = regs->dstat; 121952130Smckusick while (msg != (dstat = regs->dstat)) 122052130Smckusick msg = dstat; 122152130Smckusick if (dstat & (SII_CI | SII_DI)) 122252130Smckusick goto again; 122352130Smckusick 122452130Smckusick if (sc->sc_target < 0) { 122552130Smckusick /* look for another device that is ready */ 122652130Smckusick for (i = 0; i < SII_NCMD; i++) { 122752130Smckusick /* don't restart a disconnected command */ 122852130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 122952130Smckusick continue; 123052130Smckusick sii_StartCmd(sc, i); 123152130Smckusick break; 123252130Smckusick } 123352130Smckusick } 123452130Smckusick return; 123552130Smckusick 123652130Smckusick abort: 123752130Smckusick /* jump here to abort the current command */ 123852130Smckusick printf("sii%d: device %d: current command terminated\n", 123952130Smckusick sc - sii_softc, sc->sc_target); 124052130Smckusick #ifdef DEBUG 124152130Smckusick sii_DumpLog(); 124252130Smckusick #endif 124352130Smckusick 124452130Smckusick if ((cstat = regs->cstat) & SII_CON) { 124552130Smckusick /* try to send an abort msg for awhile */ 124652130Smckusick regs->dstat = SII_DNE; 124752130Smckusick regs->data = SCSI_ABORT; 124852130Smckusick regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 124952130Smckusick SII_MSG_OUT_PHASE; 125052130Smckusick MachEmptyWriteBuffer(); 125152130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 125252130Smckusick (dstat & (SII_DNE | SII_PHASE_MSK)) == 125352130Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 125452130Smckusick 2 * SII_WAIT_COUNT, i); 125552130Smckusick #ifdef DEBUG 125652130Smckusick if (sii_debug > 0) 125752130Smckusick printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 125852130Smckusick #endif 125952130Smckusick if (dstat & (SII_DNE | SII_PHASE_MSK) == 126052130Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) { 126152130Smckusick /* disconnect if command in progress */ 126252130Smckusick regs->comm = SII_DISCON; 126352130Smckusick MachEmptyWriteBuffer(); 126452130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 126552130Smckusick !(cstat & SII_CON), SII_WAIT_COUNT, i); 126652130Smckusick } 126752130Smckusick } else { 126852130Smckusick #ifdef DEBUG 126952130Smckusick if (sii_debug > 0) 127052130Smckusick printf("Abort: cs %x\n", cstat); 127152130Smckusick #endif 127252130Smckusick } 127352130Smckusick regs->cstat = 0xffff; 127452130Smckusick regs->dstat = 0xffff; 127552130Smckusick regs->comm = 0; 127652130Smckusick MachEmptyWriteBuffer(); 127752130Smckusick 127852130Smckusick i = sc->sc_target; 127952130Smckusick sc->sc_target = -1; 128052130Smckusick sii_CmdDone(sc, i, EIO); 128152130Smckusick #ifdef DEBUG 128252130Smckusick if (sii_debug > 4) 128352130Smckusick printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 128452130Smckusick #endif 128552130Smckusick } 128652130Smckusick 128752130Smckusick static void 128852130Smckusick sii_StateChg(sc, cstat) 128952130Smckusick register struct siisoftc *sc; 129052130Smckusick register unsigned cstat; 129152130Smckusick { 129252130Smckusick register SIIRegs *regs = sc->sc_regs; 129352130Smckusick register State *state; 129452130Smckusick register int i; 129552130Smckusick 129652130Smckusick #ifdef DEBUG 129752130Smckusick if (sii_debug > 4) 129852130Smckusick printf("SCH: "); 129952130Smckusick #endif 130052130Smckusick 130152130Smckusick switch (cstat & SII_STATE_MSK) { 130252130Smckusick case 0: 130352130Smckusick /* disconnect */ 130452130Smckusick i = sc->sc_target; 130552130Smckusick sc->sc_target = -1; 130652130Smckusick #ifdef DEBUG 130752130Smckusick if (sii_debug > 4) 130852130Smckusick printf("disconn %d ", i); 130952130Smckusick #endif 131052130Smckusick if (i >= 0 && !sc->sc_st[i].prevComm) { 131152130Smckusick printf("sii%d: device %d: spurrious disconnect (%d)\n", 131252130Smckusick sc - sii_softc, i, regs->slcsr); 131352130Smckusick sc->sc_st[i].prevComm = 0; 131452130Smckusick } 131552130Smckusick break; 131652130Smckusick 131752130Smckusick case SII_CON: 131852130Smckusick /* connected as initiator */ 131952130Smckusick i = regs->slcsr; 132052130Smckusick if (sc->sc_target == i) 132152130Smckusick break; 132252130Smckusick printf("sii%d: device %d: connect to device %d??\n", 132352130Smckusick sc - sii_softc, sc->sc_target, i); 132452130Smckusick sc->sc_target = i; 132552130Smckusick break; 132652130Smckusick 132752130Smckusick case SII_DST: 132852130Smckusick /* 132952130Smckusick * Wait for CON to become valid, 133052130Smckusick * chip is slow sometimes. 133152130Smckusick */ 133252130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 133352130Smckusick cstat & SII_CON, SII_WAIT_COUNT, i); 133452130Smckusick if (!(cstat & SII_CON)) 133552130Smckusick panic("sii resel"); 133652130Smckusick /* FALLTHROUGH */ 133752130Smckusick 133852130Smckusick case SII_CON | SII_DST: 133952130Smckusick /* 134052130Smckusick * Its a reselection. Save the ID and wait for 134152130Smckusick * interrupts to tell us what to do next 134252130Smckusick * (should be MSG_IN of IDENTIFY). 134352130Smckusick * NOTE: sc_target may be >= 0 if we were in 134452130Smckusick * the process of trying to start a command 134552130Smckusick * and were reselected before the select 134652130Smckusick * command finished. 134752130Smckusick */ 134852130Smckusick sc->sc_target = i = regs->destat; 134952130Smckusick regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 135052130Smckusick MachEmptyWriteBuffer(); 135152130Smckusick state = &sc->sc_st[i]; 135252130Smckusick if (!state->prevComm) { 135352130Smckusick printf("sii%d: device %d: spurrious reselection\n", 135452130Smckusick sc - sii_softc, i); 135552130Smckusick break; 135652130Smckusick } 135752130Smckusick state->prevComm = 0; 135852130Smckusick #ifdef DEBUG 135952130Smckusick if (sii_debug > 4) 136052130Smckusick printf("resel %d ", sc->sc_target); 136152130Smckusick #endif 136252130Smckusick break; 136352130Smckusick 136452130Smckusick #ifdef notyet 136552130Smckusick case SII_DST | SII_TGT: 136652130Smckusick case SII_CON | SII_DST | SII_TGT: 136752130Smckusick /* connected as target */ 136852130Smckusick printf("sii%d: Selected by device %d as target!!\n", 136952130Smckusick sc - sii_softc, regs->destat); 137052130Smckusick regs->comm = SII_DISCON; 137152130Smckusick MachEmptyWriteBuffer(); 137252130Smckusick SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 137352130Smckusick SII_WAIT_COUNT, i); 137452130Smckusick regs->cstat = 0xffff; 137552130Smckusick regs->dstat = 0xffff; 137652130Smckusick regs->comm = 0; 137752130Smckusick break; 137852130Smckusick #endif 137952130Smckusick 138052130Smckusick default: 138152130Smckusick printf("sii%d: Unknown state change (cs %x)!!\n", 138252130Smckusick sc - sii_softc, cstat); 138352130Smckusick #ifdef DEBUG 138452130Smckusick sii_DumpLog(); 138552130Smckusick #endif 138652130Smckusick } 138752130Smckusick } 138852130Smckusick 138952130Smckusick /* 139052130Smckusick * Read one byte of data. 139152130Smckusick */ 139252130Smckusick static int 139352130Smckusick sii_GetByte(regs, phase) 139452130Smckusick register SIIRegs *regs; 139552130Smckusick int phase; 139652130Smckusick { 139752130Smckusick register unsigned dstat; 139852130Smckusick register unsigned state; 139952130Smckusick #ifdef PROGXFER 140052130Smckusick register unsigned data; 140152130Smckusick 140252130Smckusick dstat = regs->dstat; 140352130Smckusick state = regs->cstat & SII_STATE_MSK; 140452130Smckusick regs->dmctrl = 0; 140552130Smckusick if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 140652130Smckusick regs->comm = state | phase; 140752130Smckusick MachEmptyWriteBuffer(); 140852130Smckusick /* wait a short time for IBF */ 140952130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 141052130Smckusick SII_WAIT_COUNT, i); 141152130Smckusick #ifdef DEBUG 141252130Smckusick if (!(dstat & SII_IBF)) 141352130Smckusick printf("status no IBF\n"); 141452130Smckusick #endif 141552130Smckusick } 141652130Smckusick data = regs->data; 141752130Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 141852130Smckusick printf("sii_GetByte: DNE set 5\n"); 141952130Smckusick sii_DumpLog(); 142052130Smckusick regs->dstat = SII_DNE; 142152130Smckusick } 142252130Smckusick regs->comm = SII_INXFER | state | phase; 142352130Smckusick MachEmptyWriteBuffer(); 142452130Smckusick 142552130Smckusick /* wait a short time for XFER complete */ 142652130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 142752130Smckusick SII_WAIT_COUNT, i); 142852130Smckusick 142952130Smckusick if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) { 143052130Smckusick #ifdef DEBUG 143152130Smckusick if (sii_debug > 4) 143252130Smckusick printf("cnt0 %d\n", i); 143352130Smckusick #endif 143452130Smckusick printf("MsgIn %x ?? ds %x cm %x i %d\n", 143552130Smckusick data, dstat, comm, i); /* XXX */ 143652130Smckusick sii_DumpLog(); /* XXX */ 143752130Smckusick panic("status"); /* XXX */ 143852130Smckusick goto again; 143952130Smckusick } 144052130Smckusick 144152130Smckusick /* clear the DNE, other errors handled later */ 144252130Smckusick regs->dstat = SII_DNE; 144352130Smckusick MachEmptyWriteBuffer(); 144452130Smckusick return (data); 144552130Smckusick 144652130Smckusick #else /* PROGXFER */ 144752130Smckusick register int i; 144852130Smckusick 144952130Smckusick state = regs->cstat & SII_STATE_MSK; 145052130Smckusick regs->dmctrl = 0; 145152130Smckusick if (regs->dstat & SII_DNE) { 145252130Smckusick printf("sii_GetByte: DNE cs %x ds %x cm %x\n", 145352130Smckusick regs->cstat, regs->dstat, regs->comm); /* XXX */ 145452130Smckusick regs->dstat = SII_DNE; 145552130Smckusick } 145652130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 145752130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 145852130Smckusick regs->dmlotc = 1; 145952130Smckusick regs->comm = SII_DMA | SII_INXFER | state | phase; 146052130Smckusick MachEmptyWriteBuffer(); 146152130Smckusick 146252130Smckusick /* wait a short time for XFER complete */ 146352130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 146452130Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 146552130Smckusick SII_WAIT_COUNT, i); 146652130Smckusick 146752130Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { 146852130Smckusick printf("sii_GetByte: ds %x cm %x i %d lotc %d\n", 146952130Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 147052130Smckusick sii_DumpLog(); /* XXX */ 147152130Smckusick return (-1); 147252130Smckusick } 147352130Smckusick 147452130Smckusick /* clear the DNE, other errors handled later */ 147552130Smckusick regs->dstat = SII_DNE; 147652130Smckusick MachEmptyWriteBuffer(); 147752130Smckusick 147852130Smckusick /* return one byte of data (optimized CopyFromBuffer()) */ 147952130Smckusick return (*(volatile u_short *)SII_BUF_ADDR & 0xFF); 148052130Smckusick #endif /* PROGXFER */ 148152130Smckusick } 148252130Smckusick 148352130Smckusick /* 148452130Smckusick * Exchange messages to initiate synchronous data transfers. 148552130Smckusick */ 148652130Smckusick static void 148752130Smckusick sii_DoSync(regs, state) 148852130Smckusick register SIIRegs *regs; 148952130Smckusick register State *state; 149052130Smckusick { 149152130Smckusick register unsigned dstat; 149252130Smckusick register int i; 149352130Smckusick unsigned len; 149452130Smckusick 149552130Smckusick printf("sii_DoSync: per %d req/ack %d\n", 149652130Smckusick sii_buf[3], sii_buf[4]); /* XXX */ 149752130Smckusick len = sii_buf[4]; 149852130Smckusick if (len > 3) 149952130Smckusick len = 3; /* SII chip can only handle 3 max */ 150052130Smckusick 150152130Smckusick sii_buf[0] = SCSI_EXTENDED_MSG; 150252130Smckusick sii_buf[1] = 3; /* message length */ 150352130Smckusick sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 150452130Smckusick sii_buf[4] = len; 150552130Smckusick CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 150652130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 150752130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 150852130Smckusick regs->dmlotc = 5; 150952130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_ATN | 151052130Smckusick (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 151152130Smckusick MachEmptyWriteBuffer(); 151252130Smckusick 151352130Smckusick /* wait a short time for XFER complete */ 151452130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 151552130Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 151652130Smckusick SII_WAIT_COUNT, i); 151752130Smckusick 151852130Smckusick if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 151952130Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 152052130Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 152152130Smckusick sii_DumpLog(); /* XXX */ 152252130Smckusick return; 152352130Smckusick } 152452130Smckusick 152552130Smckusick /* clear the DNE, other errors handled later */ 152652130Smckusick regs->dstat = SII_DNE; 152752130Smckusick regs->comm = regs->comm & SII_STATE_MSK; 152852130Smckusick MachEmptyWriteBuffer(); 152952130Smckusick 153052130Smckusick state->dmaReqAck = len; 153152130Smckusick } 153252130Smckusick 153352130Smckusick /* 153452130Smckusick * Issue the sequence of commands to the controller to start DMA. 153552130Smckusick * NOTE: the data buffer should be word-aligned for DMA out. 153652130Smckusick */ 153752130Smckusick static void 153852130Smckusick sii_StartDMA(regs, phase, dmaAddr, size) 153952130Smckusick register SIIRegs *regs; /* which SII to use */ 154052130Smckusick int phase; /* phase to send/receive data */ 154152130Smckusick u_short *dmaAddr; /* DMA buffer address */ 154252130Smckusick int size; /* # of bytes to transfer */ 154352130Smckusick { 154452130Smckusick 154552130Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 154652130Smckusick printf("sii_StartDMA: DNE set\n"); 154752130Smckusick sii_DumpLog(); 154852130Smckusick regs->dstat = SII_DNE; 154952130Smckusick } 155052130Smckusick regs->dmaddrl = ((unsigned)dmaAddr >> 1); 155152130Smckusick regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; 155252130Smckusick regs->dmlotc = size; 155352130Smckusick regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 155452130Smckusick phase; 155552130Smckusick MachEmptyWriteBuffer(); 155652130Smckusick 155752130Smckusick #ifdef DEBUG 155852130Smckusick if (sii_debug > 5) { 155952130Smckusick printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 156052130Smckusick regs->cstat, regs->dstat, regs->comm, size); 156152130Smckusick } 156252130Smckusick #endif 156352130Smckusick } 156452130Smckusick 156552130Smckusick /* 156652130Smckusick * Call the device driver's 'done' routine to let it know the command is done. 156752130Smckusick * The 'done' routine may try to start another command. 156852130Smckusick * To be fair, we should start pending commands for other devices 156952130Smckusick * before allowing the same device to start another command. 157052130Smckusick */ 157152130Smckusick static void 157252130Smckusick sii_CmdDone(sc, target, error) 157352130Smckusick register struct siisoftc *sc; /* which SII to use */ 157452130Smckusick int target; /* which device is done */ 157552130Smckusick int error; /* error code if any errors */ 157652130Smckusick { 157752130Smckusick register ScsiCmd *scsicmd; 157852130Smckusick register int i; 157952130Smckusick 158052130Smckusick scsicmd = sc->sc_cmd[target]; 158152130Smckusick #ifdef DIAGNOSTIC 158252130Smckusick if (target < 0 || !scsicmd) 158352130Smckusick panic("sii_CmdDone"); 158452130Smckusick #endif 158552130Smckusick sc->sc_cmd[target] = (ScsiCmd *)0; 158652130Smckusick #ifdef DEBUG 158752130Smckusick if (sii_debug > 1) { 158852130Smckusick printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 158952130Smckusick scsicmd->sd->sd_driver->d_name, target, 159052130Smckusick scsicmd->cmd[0], error, sc->sc_st[target].buflen); 159152130Smckusick } 159252130Smckusick #endif 159352130Smckusick 159452130Smckusick /* look for another device that is ready */ 159552130Smckusick for (i = 0; i < SII_NCMD; i++) { 159652130Smckusick /* don't restart a disconnected command */ 159752130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 159852130Smckusick continue; 159952130Smckusick sii_StartCmd(sc, i); 160052130Smckusick break; 160152130Smckusick } 160252130Smckusick 160352130Smckusick (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 160452130Smckusick sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 160552130Smckusick } 160652130Smckusick 160752130Smckusick #ifdef DEBUG 160852130Smckusick sii_DumpLog() 160952130Smckusick { 161052130Smckusick register struct sii_log *lp; 161152130Smckusick 161252130Smckusick printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 161352130Smckusick sii_debug_sz); 161452130Smckusick lp = sii_logp + 1; 161552130Smckusick if (lp > &sii_log[NLOG]) 161652130Smckusick lp = sii_log; 161752130Smckusick while (lp != sii_logp) { 161852130Smckusick printf("target %d cs %x ds %x cm %x msg %x\n", 161952130Smckusick lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); 162052130Smckusick if (++lp >= &sii_log[NLOG]) 162152130Smckusick lp = sii_log; 162252130Smckusick } 162352130Smckusick } 162452130Smckusick #endif 162552130Smckusick #endif 1626