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*52754Sralph * @(#)sii.c 7.3 (Berkeley) 02/29/92 1152130Smckusick * 1252130Smckusick * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c, 13*52754Sralph * 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 */ 2152130Smckusick #include "param.h" 2252130Smckusick #include "systm.h" 2352130Smckusick #include "dkstat.h" 2452130Smckusick #include "buf.h" 2552130Smckusick #include "conf.h" 2652130Smckusick #include "errno.h" 2752130Smckusick 2852130Smckusick #include "machine/machConst.h" 2952130Smckusick #include "device.h" 3052130Smckusick #include "scsi.h" 3152130Smckusick #include "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 if (state->buflen > SII_MAX_DMA_XFER_LENGTH && 32152130Smckusick (scsicmd->flags & SCSICMD_DATA_TO_DEVICE)) 32252130Smckusick printf("sii_StartCmd: target %d dma %d\n", 32352130Smckusick target, state->buflen); /* XXX */ 32452130Smckusick } 32552130Smckusick 32652130Smckusick #ifdef DEBUG 32752130Smckusick if (sii_debug > 1) { 32852130Smckusick printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 32952130Smckusick scsicmd->sd->sd_driver->d_name, target, 33052130Smckusick scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 33152130Smckusick state->dmaDataPhase); 33252130Smckusick } 33352130Smckusick sii_debug_cmd = scsicmd->cmd[0]; 33452130Smckusick if (scsicmd->cmd[0] == SCSI_READ_EXT) { 33552130Smckusick sii_debug_bn = (scsicmd->cmd[2] << 24) | 33652130Smckusick (scsicmd->cmd[3] << 16) | 33752130Smckusick (scsicmd->cmd[4] << 8) | 33852130Smckusick scsicmd->cmd[5]; 33952130Smckusick sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 34052130Smckusick } 34152130Smckusick #endif 34252130Smckusick 34352130Smckusick /* try to select the target */ 34452130Smckusick regs = sc->sc_regs; 34552130Smckusick 34652130Smckusick /* 34752130Smckusick * Another device may have selected us; in which case, 34852130Smckusick * this command will be restarted later. 34952130Smckusick */ 35052130Smckusick if ((status = regs->dstat) & (SII_CI | SII_DI)) { 35152130Smckusick sii_DoIntr(sc, status); 35252130Smckusick return; 35352130Smckusick } 35452130Smckusick 35552130Smckusick sc->sc_target = target; 35652130Smckusick if (scsicmd->flags & SCSICMD_USE_SYNC) { 35752130Smckusick printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 35852130Smckusick /* 35952130Smckusick * Setup to send both the identify message and the synchronous 36052130Smckusick * data transfer request. 36152130Smckusick */ 36252130Smckusick sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 36352130Smckusick sii_buf[1] = SCSI_EXTENDED_MSG; 36452130Smckusick sii_buf[2] = 3; /* message length */ 36552130Smckusick sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 36652130Smckusick sii_buf[4] = 0; 36752130Smckusick sii_buf[5] = 3; /* maximum SII chip supports */ 36852130Smckusick 36952130Smckusick state->dmaCurPhase = SII_MSG_OUT_PHASE, 37052130Smckusick state->dmalen = 6; 37152130Smckusick CopyToBuffer((u_short *)sii_buf, 37252130Smckusick (volatile u_short *)SII_BUF_ADDR, 6); 37352130Smckusick regs->slcsr = target; 37452130Smckusick regs->dmctrl = 0; 37552130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 37652130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 37752130Smckusick regs->dmlotc = 6; 37852130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 37952130Smckusick SII_CON | SII_MSG_OUT_PHASE; 38052130Smckusick } else { 38152130Smckusick /* do a chained, select with ATN and programmed I/O command */ 38252130Smckusick regs->data = SCSI_DIS_REC_IDENTIFY; 38352130Smckusick regs->slcsr = target; 38452130Smckusick regs->dmctrl = 0; 38552130Smckusick regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 38652130Smckusick SII_MSG_OUT_PHASE; 38752130Smckusick } 38852130Smckusick MachEmptyWriteBuffer(); 38952130Smckusick 39052130Smckusick /* 39152130Smckusick * Wait for something to happen 39252130Smckusick * (should happen soon or we would use interrupts). 39352130Smckusick */ 39452130Smckusick SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 39552130Smckusick SII_WAIT_COUNT/2, retval); 39652130Smckusick 39752130Smckusick /* check to see if we are connected OK */ 39852130Smckusick if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 39952130Smckusick (SII_SCH | SII_CON)) { 40052130Smckusick regs->cstat = status; 40152130Smckusick MachEmptyWriteBuffer(); 40252130Smckusick 40352130Smckusick #ifdef DEBUG 40452130Smckusick sii_logp->target = target; 40552130Smckusick sii_logp->cstat = status; 40652130Smckusick sii_logp->dstat = 0; 40752130Smckusick sii_logp->comm = regs->comm; 40852130Smckusick sii_logp->msg = -1; 40952130Smckusick if (++sii_logp >= &sii_log[NLOG]) 41052130Smckusick sii_logp = sii_log; 41152130Smckusick #endif 41252130Smckusick 41352130Smckusick /* wait a short time for command phase */ 41452130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 41552130Smckusick SII_WAIT_COUNT, retval); 41652130Smckusick #ifdef DEBUG 41752130Smckusick if (sii_debug > 2) 41852130Smckusick printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 41952130Smckusick #endif 42052130Smckusick if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 42152130Smckusick (SII_MIS | SII_CMD_PHASE)) { 42252130Smckusick printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 42352130Smckusick regs->cstat, status, retval); /* XXX */ 42452130Smckusick /* process interrupt or continue until it happens */ 42552130Smckusick if (status & (SII_CI | SII_DI)) 42652130Smckusick sii_DoIntr(sc, status); 42752130Smckusick return; 42852130Smckusick } 42952130Smckusick regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 43052130Smckusick 43152130Smckusick /* send command data */ 43252130Smckusick CopyToBuffer((u_short *)state->cmd, 43352130Smckusick (volatile u_short *)state->dmaAddr[0], state->cmdlen); 43452130Smckusick sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 43552130Smckusick state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 43652130Smckusick 43752130Smckusick /* wait a little while for DMA to finish */ 43852130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 43952130Smckusick SII_WAIT_COUNT, retval); 44052130Smckusick #ifdef DEBUG 44152130Smckusick if (sii_debug > 2) 44252130Smckusick printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 44352130Smckusick #endif 44452130Smckusick if (status & (SII_CI | SII_DI)) 44552130Smckusick sii_DoIntr(sc, status); 44652130Smckusick #ifdef DEBUG 44752130Smckusick if (sii_debug > 2) 44852130Smckusick printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 44952130Smckusick #endif 45052130Smckusick return; 45152130Smckusick } 45252130Smckusick 45352130Smckusick /* 45452130Smckusick * Another device may have selected us; in which case, 45552130Smckusick * this command will be restarted later. 45652130Smckusick */ 45752130Smckusick if (status & (SII_CI | SII_DI)) { 45852130Smckusick sii_DoIntr(sc, regs->dstat); 45952130Smckusick return; 46052130Smckusick } 46152130Smckusick 46252130Smckusick /* 46352130Smckusick * Disconnect if selection command still in progress. 46452130Smckusick */ 46552130Smckusick if (status & SII_SIP) { 46652130Smckusick error = ENXIO; /* device didn't respond */ 46752130Smckusick regs->comm = SII_DISCON; 46852130Smckusick MachEmptyWriteBuffer(); 46952130Smckusick SII_WAIT_UNTIL(status, regs->cstat, 47052130Smckusick !(status & (SII_CON | SII_SIP)), 47152130Smckusick SII_WAIT_COUNT, retval); 47252130Smckusick } else 47352130Smckusick error = EBUSY; /* couldn't get the bus */ 47452130Smckusick #ifdef DEBUG 47552130Smckusick if (sii_debug > 0) 47652130Smckusick printf("sii_StartCmd: Couldn't select target %d error %d\n", 47752130Smckusick target, error); 47852130Smckusick #endif 47952130Smckusick sc->sc_target = -1; 48052130Smckusick regs->cstat = 0xffff; 48152130Smckusick regs->dstat = 0xffff; 48252130Smckusick regs->comm = 0; 48352130Smckusick MachEmptyWriteBuffer(); 48452130Smckusick sii_CmdDone(sc, target, error); 48552130Smckusick } 48652130Smckusick 48752130Smckusick /* 48852130Smckusick * Process interrupt conditions. 48952130Smckusick */ 49052130Smckusick static void 49152130Smckusick sii_DoIntr(sc, dstat) 49252130Smckusick register struct siisoftc *sc; 49352130Smckusick register unsigned dstat; 49452130Smckusick { 49552130Smckusick register SIIRegs *regs = sc->sc_regs; 49652130Smckusick register State *state; 49752130Smckusick register unsigned cstat; 49852130Smckusick register int i; 49952130Smckusick unsigned comm, msg; 50052130Smckusick 50152130Smckusick again: 50252130Smckusick comm = regs->comm; 50352130Smckusick 50452130Smckusick #ifdef DEBUG 50552130Smckusick if (sii_debug > 3) 50652130Smckusick printf("sii_DoIntr: cs %x, ds %x cm %x ", 50752130Smckusick regs->cstat, dstat, comm); 50852130Smckusick sii_logp->target = sc->sc_target; 50952130Smckusick sii_logp->cstat = regs->cstat; 51052130Smckusick sii_logp->dstat = dstat; 51152130Smckusick sii_logp->comm = comm; 51252130Smckusick sii_logp->msg = -1; 51352130Smckusick if (++sii_logp >= &sii_log[NLOG]) 51452130Smckusick sii_logp = sii_log; 51552130Smckusick #endif 51652130Smckusick 51752130Smckusick regs->dstat = dstat; /* acknowledge everything */ 51852130Smckusick MachEmptyWriteBuffer(); 51952130Smckusick 52052130Smckusick if (dstat & SII_CI) { 52152130Smckusick /* deglitch cstat register */ 52252130Smckusick msg = regs->cstat; 52352130Smckusick while (msg != (cstat = regs->cstat)) 52452130Smckusick msg = cstat; 52552130Smckusick regs->cstat = cstat; /* acknowledge everything */ 52652130Smckusick MachEmptyWriteBuffer(); 52752130Smckusick #ifdef DEBUG 52852130Smckusick if (sii_logp > sii_log) 52952130Smckusick sii_logp[-1].cstat = cstat; 53052130Smckusick else 53152130Smckusick sii_log[NLOG - 1].cstat = cstat; 53252130Smckusick #endif 53352130Smckusick 53452130Smckusick /* check for a BUS RESET */ 53552130Smckusick if (cstat & SII_RST) { 53652130Smckusick printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 53752130Smckusick /* need to flush disconnected commands */ 53852697Sralph for (i = 0; i < SII_NCMD; i++) { 53952697Sralph if (!sc->sc_cmd[i]) 54052697Sralph continue; 54152130Smckusick sii_CmdDone(sc, i, EIO); 54252697Sralph } 54352130Smckusick /* rearbitrate synchronous offset */ 54452130Smckusick for (i = 0; i < SII_NCMD; i++) 54552130Smckusick sc->sc_st[i].dmaReqAck = 0; 54652130Smckusick sc->sc_target = -1; 54752130Smckusick return; 54852130Smckusick } 54952130Smckusick 55052130Smckusick #ifdef notdef 55152130Smckusick /* 55252130Smckusick * Check for a BUS ERROR. 55352130Smckusick * According to DEC, this feature doesn't really work 55452130Smckusick * and to just clear the bit if it's set. 55552130Smckusick */ 55652130Smckusick if (cstat & SII_BER) { 55752130Smckusick } 55852130Smckusick #endif 55952130Smckusick 56052130Smckusick /* check for state change */ 56152130Smckusick if (cstat & SII_SCH) { 56252130Smckusick sii_StateChg(sc, cstat); 56352130Smckusick comm = regs->comm; 56452130Smckusick } 56552130Smckusick } 56652130Smckusick 56752130Smckusick /* check for DMA completion */ 56852130Smckusick if (dstat & SII_DNE) { 56952130Smckusick u_short *dma; 57052130Smckusick char *buf; 57152130Smckusick 57252130Smckusick /* check for a PARITY ERROR */ 57352130Smckusick if (dstat & SII_IPE) { 57452130Smckusick printf("sii%d: Parity error!!\n", sc - sii_softc); 57552130Smckusick goto abort; 57652130Smckusick } 57752130Smckusick /* 57852130Smckusick * There is a race condition with SII_SCH. There is a short 57952130Smckusick * window between the time a SII_SCH is seen after a disconnect 58052130Smckusick * and when the SII_SCH is cleared. A reselect can happen 58152130Smckusick * in this window and we will clear the SII_SCH without 58252130Smckusick * processing the reconnect. 58352130Smckusick */ 58452130Smckusick if (sc->sc_target < 0) { 58552130Smckusick cstat = regs->cstat; 58652130Smckusick printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 58752130Smckusick sc - sii_softc, sc->sc_target, 58852130Smckusick regs->slcsr, regs->destat, 58952130Smckusick cstat); /* XXX */ 59052130Smckusick if (cstat & SII_DST) { 59152130Smckusick sc->sc_target = regs->destat; 59252130Smckusick state->prevComm = 0; 59352130Smckusick } else 59452130Smckusick panic("sc_target 1"); 59552130Smckusick } 59652130Smckusick state = &sc->sc_st[sc->sc_target]; 59752130Smckusick /* dmalen = amount left to transfer, i = amount transfered */ 59852130Smckusick i = state->dmalen; 59952130Smckusick state->dmalen = 0; 60052130Smckusick state->dmaCurPhase = -1; 60152130Smckusick #ifdef DEBUG 60252130Smckusick if (sii_debug > 4) { 60352130Smckusick printf("DNE: amt %d ", i); 60452130Smckusick if (!(dstat & SII_TCZ)) 60552130Smckusick printf("no TCZ?? (%d) ", regs->dmlotc); 60652130Smckusick } else if (!(dstat & SII_TCZ)) { 60752130Smckusick printf("sii%d: device %d: no TCZ?? (%d)\n", 60852130Smckusick sc - sii_softc, sc->sc_target, regs->dmlotc); 60952130Smckusick sii_DumpLog(); /* XXX */ 61052130Smckusick } 61152130Smckusick #endif 61252130Smckusick switch (comm & SII_PHASE_MSK) { 61352130Smckusick case SII_CMD_PHASE: 61452130Smckusick state->cmdlen -= i; 61552130Smckusick break; 61652130Smckusick 61752130Smckusick case SII_DATA_IN_PHASE: 61852130Smckusick /* check for more data for the same phase */ 61952130Smckusick dma = state->dmaAddr[state->dmaBufIndex]; 62052130Smckusick buf = state->buf; 62152130Smckusick state->buf += i; 62252130Smckusick state->buflen -= i; 62352130Smckusick if (state->buflen > 0 && !(dstat & SII_MIS)) { 62452130Smckusick int len; 62552130Smckusick 62652130Smckusick /* start reading next chunk */ 62752130Smckusick len = state->buflen; 62852130Smckusick if (len > SII_MAX_DMA_XFER_LENGTH) 62952130Smckusick len = SII_MAX_DMA_XFER_LENGTH; 63052130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 63152130Smckusick sii_StartDMA(regs, 63252130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 63352130Smckusick state->dmaAddr[state->dmaBufIndex], 63452130Smckusick state->dmalen = len); 63552130Smckusick dstat &= ~(SII_IBF | SII_TBE); 63652130Smckusick } 63752130Smckusick /* copy in the data */ 63852130Smckusick CopyFromBuffer((volatile u_short *)dma, buf, i); 63952130Smckusick break; 64052130Smckusick 64152130Smckusick case SII_DATA_OUT_PHASE: 64252130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 64352130Smckusick state->buf += i; 64452130Smckusick state->buflen -= i; 64552130Smckusick 64652130Smckusick /* check for more data for the same phase */ 64752130Smckusick if (state->buflen <= 0 || (dstat & SII_MIS)) 64852130Smckusick break; 64952130Smckusick 65052130Smckusick /* start next chunk */ 65152130Smckusick i = state->buflen; 65252130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) { 65352130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 65452130Smckusick SII_DATA_OUT_PHASE, 65552130Smckusick state->dmaAddr[state->dmaBufIndex], 65652130Smckusick state->dmalen = 65752130Smckusick SII_MAX_DMA_XFER_LENGTH); 65852130Smckusick /* prepare for next chunk */ 65952130Smckusick i -= SII_MAX_DMA_XFER_LENGTH; 66052130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 66152130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 66252130Smckusick CopyToBuffer((u_short *)(state->buf + 66352130Smckusick SII_MAX_DMA_XFER_LENGTH), 66452130Smckusick (volatile u_short *) 66552130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 66652130Smckusick } else { 66752130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 66852130Smckusick SII_DATA_OUT_PHASE, 66952130Smckusick state->dmaAddr[state->dmaBufIndex], 67052130Smckusick state->dmalen = i); 67152130Smckusick } 67252130Smckusick dstat &= ~(SII_IBF | SII_TBE); 67352130Smckusick break; 67452130Smckusick 67552130Smckusick default: 67652130Smckusick printf("sii%d: device %d: unexpected DNE\n", 67752130Smckusick sc - sii_softc, sc->sc_target); 67852130Smckusick #ifdef DEBUG 67952130Smckusick sii_DumpLog(); 68052130Smckusick #endif 68152130Smckusick } 68252130Smckusick } 68352130Smckusick 68452130Smckusick /* check for phase change or another MsgIn/Out */ 68552130Smckusick if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 68652130Smckusick /* 68752130Smckusick * There is a race condition with SII_SCH. There is a short 68852130Smckusick * window between the time a SII_SCH is seen after a disconnect 68952130Smckusick * and when the SII_SCH is cleared. A reselect can happen 69052130Smckusick * in this window and we will clear the SII_SCH without 69152130Smckusick * processing the reconnect. 69252130Smckusick */ 69352130Smckusick if (sc->sc_target < 0) { 69452130Smckusick cstat = regs->cstat; 69552130Smckusick printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 69652130Smckusick sc - sii_softc, sc->sc_target, 69752130Smckusick regs->slcsr, regs->destat, 69852130Smckusick cstat, dstat); /* XXX */ 69952130Smckusick if (cstat & SII_DST) { 70052130Smckusick sc->sc_target = regs->destat; 70152130Smckusick state->prevComm = 0; 70252130Smckusick } else 70352130Smckusick panic("sc_target 2"); 70452130Smckusick } 70552130Smckusick state = &sc->sc_st[sc->sc_target]; 70652130Smckusick switch (dstat & SII_PHASE_MSK) { 70752130Smckusick case SII_CMD_PHASE: 70852130Smckusick if (state->dmaPrevPhase >= 0) { 70952130Smckusick /* restart DMA after disconnect/reconnect */ 71052130Smckusick if (state->dmaPrevPhase != SII_CMD_PHASE) { 71152130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 71252130Smckusick sc - sii_softc, sc->sc_target); 71352130Smckusick goto abort; 71452130Smckusick } 71552130Smckusick state->dmaCurPhase = SII_CMD_PHASE; 71652130Smckusick state->dmaPrevPhase = -1; 71752130Smckusick regs->dmaddrl = state->dmaAddrL; 71852130Smckusick regs->dmaddrh = state->dmaAddrH; 71952130Smckusick regs->dmlotc = state->dmaCnt; 72052130Smckusick if (state->dmaCnt & 1) 72152130Smckusick regs->dmabyte = state->dmaByte; 72252130Smckusick regs->comm = SII_DMA | SII_INXFER | 72352130Smckusick (comm & SII_STATE_MSK) | SII_CMD_PHASE; 72452130Smckusick MachEmptyWriteBuffer(); 72552130Smckusick #ifdef DEBUG 72652130Smckusick if (sii_debug > 4) 72752130Smckusick printf("Cmd dcnt %d dadr %x ", 72852130Smckusick state->dmaCnt, 72952130Smckusick (state->dmaAddrH << 16) | 73052130Smckusick state->dmaAddrL); 73152130Smckusick #endif 73252130Smckusick } else { 73352130Smckusick /* send command data */ 73452130Smckusick i = state->cmdlen; 73552130Smckusick if (i == 0) { 73652130Smckusick printf("sii%d: device %d: cmd count exceeded\n", 73752130Smckusick sc - sii_softc, sc->sc_target); 73852130Smckusick goto abort; 73952130Smckusick } 74052130Smckusick CopyToBuffer((u_short *)state->cmd, 74152130Smckusick (volatile u_short *)state->dmaAddr[0], 74252130Smckusick i); 74352130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 74452130Smckusick SII_CMD_PHASE, state->dmaAddr[0], 74552130Smckusick state->dmalen = i); 74652130Smckusick } 74752130Smckusick /* wait a short time for XFER complete */ 74852130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 74952130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 75052130Smckusick if (dstat & (SII_CI | SII_DI)) { 75152130Smckusick #ifdef DEBUG 75252130Smckusick if (sii_debug > 4) 75352130Smckusick printf("cnt %d\n", i); 75452130Smckusick else if (sii_debug > 0) 75552130Smckusick printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 75652130Smckusick dstat, i); 75752130Smckusick #endif 75852130Smckusick goto again; 75952130Smckusick } 76052130Smckusick break; 76152130Smckusick 76252130Smckusick case SII_DATA_IN_PHASE: 76352130Smckusick case SII_DATA_OUT_PHASE: 76452130Smckusick regs->dmctrl = state->dmaReqAck; 76552130Smckusick if (state->cmdlen > 0) { 76652130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 76752130Smckusick sc - sii_softc, sc->sc_target, 76852130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 76952130Smckusick state->cmdlen); 77052130Smckusick state->cmdlen = 0; 77152130Smckusick #ifdef DEBUG 77252130Smckusick sii_DumpLog(); 77352130Smckusick #endif 77452130Smckusick } 77552130Smckusick if (state->dmaPrevPhase >= 0) { 77652130Smckusick /* restart DMA after disconnect/reconnect */ 77752130Smckusick if (state->dmaPrevPhase != 77852130Smckusick (dstat & SII_PHASE_MSK)) { 77952130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 78052130Smckusick sc - sii_softc, sc->sc_target); 78152130Smckusick goto abort; 78252130Smckusick } 78352130Smckusick state->dmaCurPhase = state->dmaPrevPhase; 78452130Smckusick state->dmaPrevPhase = -1; 78552130Smckusick regs->dmaddrl = state->dmaAddrL; 78652130Smckusick regs->dmaddrh = state->dmaAddrH; 78752130Smckusick regs->dmlotc = state->dmaCnt; 78852130Smckusick if (state->dmaCnt & 1) 78952130Smckusick regs->dmabyte = state->dmaByte; 79052130Smckusick regs->comm = SII_DMA | SII_INXFER | 79152130Smckusick (comm & SII_STATE_MSK) | 79252130Smckusick state->dmaCurPhase; 79352130Smckusick MachEmptyWriteBuffer(); 79452130Smckusick #ifdef DEBUG 79552130Smckusick if (sii_debug > 4) 79652130Smckusick printf("Data %d dcnt %d dadr %x ", 79752130Smckusick state->dmaDataPhase, 79852130Smckusick state->dmaCnt, 79952130Smckusick (state->dmaAddrH << 16) | 80052130Smckusick state->dmaAddrL); 80152130Smckusick #endif 80252130Smckusick break; 80352130Smckusick } 80452130Smckusick if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 80552130Smckusick printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 80652130Smckusick sc - sii_softc, sc->sc_target, 80752130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0]); 80852130Smckusick goto abort; 80952130Smckusick } 81052130Smckusick #ifdef DEBUG 81152130Smckusick if (sii_debug > 4) { 81252130Smckusick printf("Data %d ", state->dmaDataPhase); 81352130Smckusick if (sii_debug > 5) 81452130Smckusick printf("\n"); 81552130Smckusick } 81652130Smckusick #endif 81752130Smckusick i = state->buflen; 81852130Smckusick if (i == 0) { 81952130Smckusick printf("sii%d: device %d: data count exceeded\n", 82052130Smckusick sc - sii_softc, sc->sc_target); 82152130Smckusick goto abort; 82252130Smckusick } 82352130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 82452130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 82552130Smckusick if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 82652130Smckusick sii_StartDMA(regs, 82752130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 82852130Smckusick state->dmaAddr[state->dmaBufIndex], 82952130Smckusick state->dmalen = i); 83052130Smckusick break; 83152130Smckusick } 83252130Smckusick /* start first chunk */ 83352130Smckusick if (state->flags & FIRST_DMA) { 83452130Smckusick state->flags &= ~FIRST_DMA; 83552130Smckusick CopyToBuffer((u_short *)state->buf, 83652130Smckusick (volatile u_short *) 83752130Smckusick state->dmaAddr[state->dmaBufIndex], i); 83852130Smckusick } 83952130Smckusick sii_StartDMA(regs, 84052130Smckusick state->dmaCurPhase = SII_DATA_OUT_PHASE, 84152130Smckusick state->dmaAddr[state->dmaBufIndex], 84252130Smckusick state->dmalen = i); 84352130Smckusick i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 84452130Smckusick if (i > 0) { 84552130Smckusick /* prepare for next chunk */ 84652130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 84752130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 84852130Smckusick CopyToBuffer((u_short *)(state->buf + 84952130Smckusick SII_MAX_DMA_XFER_LENGTH), 85052130Smckusick (volatile u_short *) 85152130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 85252130Smckusick } 85352130Smckusick break; 85452130Smckusick 85552130Smckusick case SII_STATUS_PHASE: 85652130Smckusick if (state->cmdlen > 0) { 85752130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 85852130Smckusick sc - sii_softc, sc->sc_target, 85952130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 86052130Smckusick state->cmdlen); 86152130Smckusick state->cmdlen = 0; 86252130Smckusick #ifdef DEBUG 86352130Smckusick sii_DumpLog(); 86452130Smckusick #endif 86552130Smckusick } 86652130Smckusick 86752130Smckusick /* read amount transfered if DMA didn't finish */ 86852130Smckusick if (state->dmalen > 0) { 86952130Smckusick i = state->dmalen - regs->dmlotc; 87052130Smckusick state->dmalen = 0; 87152130Smckusick state->dmaCurPhase = -1; 87252130Smckusick regs->dmlotc = 0; 87352130Smckusick regs->comm = comm & 87452130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 87552130Smckusick MachEmptyWriteBuffer(); 87652130Smckusick regs->dstat = SII_DNE; 87752130Smckusick MachEmptyWriteBuffer(); 87852130Smckusick #ifdef DEBUG 87952130Smckusick if (sii_debug > 4) 88052130Smckusick printf("DMA amt %d ", i); 88152130Smckusick #endif 88252130Smckusick switch (comm & SII_PHASE_MSK) { 88352130Smckusick case SII_DATA_IN_PHASE: 88452130Smckusick /* copy in the data */ 88552130Smckusick CopyFromBuffer((volatile u_short *) 88652130Smckusick state->dmaAddr[state->dmaBufIndex], 88752130Smckusick state->buf, i); 88852130Smckusick 88952130Smckusick case SII_CMD_PHASE: 89052130Smckusick case SII_DATA_OUT_PHASE: 89152130Smckusick state->buflen -= i; 89252130Smckusick } 89352130Smckusick } 89452130Smckusick 89552130Smckusick /* read a one byte status message */ 89652130Smckusick state->statusByte = msg = 89752130Smckusick sii_GetByte(regs, SII_STATUS_PHASE); 89852130Smckusick if (msg < 0) { 89952130Smckusick dstat = regs->dstat; 90052130Smckusick goto again; 90152130Smckusick } 90252130Smckusick #ifdef DEBUG 90352130Smckusick if (sii_debug > 4) 90452130Smckusick printf("Status %x ", msg); 90552130Smckusick if (sii_logp > sii_log) 90652130Smckusick sii_logp[-1].msg = msg; 90752130Smckusick else 90852130Smckusick sii_log[NLOG - 1].msg = msg; 90952130Smckusick #endif 91052130Smckusick 91152130Smckusick /* do a quick wait for COMMAND_COMPLETE */ 91252130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 91352130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 91452130Smckusick if (dstat & (SII_CI | SII_DI)) { 91552130Smckusick #ifdef DEBUG 91652130Smckusick if (sii_debug > 4) 91752130Smckusick printf("cnt2 %d\n", i); 91852130Smckusick #endif 91952130Smckusick goto again; 92052130Smckusick } 92152130Smckusick break; 92252130Smckusick 92352130Smckusick case SII_MSG_IN_PHASE: 92452130Smckusick /* 92552130Smckusick * Save DMA state if DMA didn't finish. 92652130Smckusick * Be careful not to save state again after reconnect 92752130Smckusick * and see RESTORE_POINTER message. 92852130Smckusick * Note that the SII DMA address is not incremented 92952130Smckusick * as DMA proceeds. 93052130Smckusick */ 93152130Smckusick if (state->dmaCurPhase > 0) { 93252130Smckusick /* save dma registers */ 93352130Smckusick state->dmaPrevPhase = state->dmaCurPhase; 93452130Smckusick state->dmaCurPhase = -1; 93552130Smckusick state->dmaCnt = i = regs->dmlotc; 93652130Smckusick if (dstat & SII_OBB) 93752130Smckusick state->dmaByte = regs->dmabyte; 93852130Smckusick if (i == 0) 93952130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 94052130Smckusick i = state->dmalen - i; 94152130Smckusick /* note: no carry from dmaddrl to dmaddrh */ 94252130Smckusick state->dmaAddrL = regs->dmaddrl + i; 94352130Smckusick state->dmaAddrH = regs->dmaddrh; 94452130Smckusick regs->comm = comm & 94552130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 94652130Smckusick MachEmptyWriteBuffer(); 94752130Smckusick regs->dstat = SII_DNE; 94852130Smckusick MachEmptyWriteBuffer(); 94952130Smckusick #ifdef DEBUG 95052130Smckusick if (sii_debug > 4) { 95152130Smckusick printf("SavP dcnt %d dadr %x ", 95252130Smckusick state->dmaCnt, 95352130Smckusick (state->dmaAddrH << 16) | 95452130Smckusick state->dmaAddrL); 95552130Smckusick if (((dstat & SII_OBB) != 0) ^ 95652130Smckusick (state->dmaCnt & 1)) 95752130Smckusick printf("OBB??? "); 95852130Smckusick } else if (sii_debug > 0) { 95952130Smckusick if (((dstat & SII_OBB) != 0) ^ 96052130Smckusick (state->dmaCnt & 1)) { 96152130Smckusick printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 96252130Smckusick dstat, state->dmaCnt); 96352130Smckusick sii_DumpLog(); 96452130Smckusick } 96552130Smckusick } 96652130Smckusick #endif 96752130Smckusick } 96852130Smckusick 96952130Smckusick /* read a one byte message */ 97052130Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 97152130Smckusick if (msg < 0) { 97252130Smckusick dstat = regs->dstat; 97352130Smckusick goto again; 97452130Smckusick } 97552130Smckusick #ifdef DEBUG 97652130Smckusick if (sii_debug > 4) 97752130Smckusick printf("MsgIn %x ", msg); 97852130Smckusick if (sii_logp > sii_log) 97952130Smckusick sii_logp[-1].msg = msg; 98052130Smckusick else 98152130Smckusick sii_log[NLOG - 1].msg = msg; 98252130Smckusick #endif 98352130Smckusick 98452130Smckusick /* process message */ 98552130Smckusick switch (msg) { 98652130Smckusick case SCSI_COMMAND_COMPLETE: 98752130Smckusick msg = sc->sc_target; 98852130Smckusick sc->sc_target = -1; 98952130Smckusick /* 99052130Smckusick * Wait a short time for disconnect. 99152130Smckusick * Don't be fooled if SII_BER happens first. 99252130Smckusick * Note: a reselect may happen here. 99352130Smckusick */ 99452130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 99552130Smckusick cstat & (SII_RST | SII_SCH), 99652130Smckusick SII_WAIT_COUNT, i); 99752130Smckusick if ((cstat & (SII_RST | SII_SCH | 99852130Smckusick SII_STATE_MSK)) == SII_SCH) { 99952130Smckusick regs->cstat = SII_SCH | SII_BER; 100052130Smckusick regs->comm = 0; 100152130Smckusick MachEmptyWriteBuffer(); 100252130Smckusick /* 100352130Smckusick * Double check that we didn't miss a 100452130Smckusick * state change between seeing it and 100552130Smckusick * clearing the SII_SCH bit. 100652130Smckusick */ 100752130Smckusick i = regs->cstat; 100852130Smckusick if (!(i & SII_SCH) && 100952130Smckusick (i & SII_STATE_MSK) != 101052130Smckusick (cstat & SII_STATE_MSK)) 101152130Smckusick sii_StateChg(sc, i); 101252130Smckusick } 101352130Smckusick #ifdef DEBUG 101452130Smckusick if (sii_debug > 4) 101552130Smckusick printf("cs %x\n", cstat); 101652130Smckusick #endif 101752130Smckusick sii_CmdDone(sc, msg, 0); 101852130Smckusick break; 101952130Smckusick 102052130Smckusick case SCSI_EXTENDED_MSG: 102152130Smckusick /* read the message length */ 102252130Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 102352130Smckusick if (msg < 0) { 102452130Smckusick dstat = regs->dstat; 102552130Smckusick goto again; 102652130Smckusick } 102752130Smckusick if (msg == 0) 102852130Smckusick msg = 256; 102952130Smckusick sii_StartDMA(regs, SII_MSG_IN_PHASE, 103052130Smckusick (u_short *)SII_BUF_ADDR, msg); 103152130Smckusick /* wait a short time for XFER complete */ 103252130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 103352130Smckusick (dstat & (SII_DNE | SII_TCZ)) == 103452130Smckusick (SII_DNE | SII_TCZ), 103552130Smckusick SII_WAIT_COUNT, i); 103652130Smckusick 103752130Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != 103852130Smckusick (SII_DNE | SII_TCZ)) { 103952130Smckusick #ifdef DEBUG 104052130Smckusick if (sii_debug > 4) 104152130Smckusick printf("cnt0 %d\n", i); 104252130Smckusick else if (sii_debug > 0) 104352130Smckusick printf("sii_DoIntr: emsg in ds %x cnt %d\n", 104452130Smckusick dstat, i); 104552130Smckusick #endif 104652130Smckusick printf("sii: ds %x cm %x i %d lotc %d\n", 104752130Smckusick dstat, comm, i, regs->dmlotc); /* XXX */ 104852130Smckusick sii_DumpLog(); /* XXX */ 104952130Smckusick goto again; 105052130Smckusick } 105152130Smckusick 105252130Smckusick /* clear the DNE, other errors handled later */ 105352130Smckusick regs->dstat = SII_DNE; 105452130Smckusick MachEmptyWriteBuffer(); 105552130Smckusick 105652130Smckusick CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, 105752130Smckusick sii_buf + 2, msg); 105852130Smckusick switch (sii_buf[2]) { 105952130Smckusick case SCSI_MODIFY_DATA_PTR: 106052130Smckusick i = (sii_buf[3] << 24) | 106152130Smckusick (sii_buf[4] << 16) | 106252130Smckusick (sii_buf[5] << 8) | 106352130Smckusick sii_buf[6]; 106452130Smckusick if (state->dmaPrevPhase >= 0) { 106552130Smckusick state->dmaAddrL += i; 106652130Smckusick state->dmaCnt -= i; 106752130Smckusick } 106852130Smckusick break; 106952130Smckusick 107052130Smckusick case SCSI_SYNCHRONOUS_XFER: 107152130Smckusick sii_DoSync(regs, state); 107252130Smckusick break; 107352130Smckusick 107452130Smckusick case SCSI_EXTENDED_IDENTIFY: 107552130Smckusick case SCSI_WIDE_XFER: 107652130Smckusick default: 107752130Smckusick reject: 107852130Smckusick /* send a reject message */ 107952130Smckusick regs->data = SCSI_MESSAGE_REJECT; 108052130Smckusick regs->comm = SII_INXFER | SII_ATN | 108152130Smckusick (regs->cstat & SII_STATE_MSK) | 108252130Smckusick SII_MSG_OUT_PHASE; 108352130Smckusick MachEmptyWriteBuffer(); 108452130Smckusick /* wait for XFER complete */ 108552130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 108652130Smckusick (dstat & 108752130Smckusick (SII_DNE | SII_PHASE_MSK)) == 108852130Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 108952130Smckusick SII_WAIT_COUNT, i); 109052130Smckusick 109152130Smckusick if ((dstat & 109252130Smckusick (SII_DNE | SII_PHASE_MSK)) != 109352130Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) 109452130Smckusick break; 109552130Smckusick regs->dstat = SII_DNE; 109652130Smckusick MachEmptyWriteBuffer(); 109752130Smckusick } 109852130Smckusick break; 109952130Smckusick 110052130Smckusick case SCSI_SAVE_DATA_POINTER: 110152130Smckusick case SCSI_RESTORE_POINTERS: 110252130Smckusick /* wait a short time for another msg */ 110352130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 110452130Smckusick dstat & (SII_CI | SII_DI), 110552130Smckusick SII_WAIT_COUNT, i); 110652130Smckusick if (dstat & (SII_CI | SII_DI)) { 110752130Smckusick #ifdef DEBUG 110852130Smckusick if (sii_debug > 4) 110952130Smckusick printf("cnt %d\n", i); 111052130Smckusick #endif 111152130Smckusick goto again; 111252130Smckusick } 111352130Smckusick break; 111452130Smckusick 111552130Smckusick case SCSI_DISCONNECT: 111652130Smckusick state->prevComm = comm; 111752130Smckusick #ifdef DEBUG 111852130Smckusick if (sii_debug > 4) 111952130Smckusick printf("disconn %d ", sc->sc_target); 112052130Smckusick #endif 112152130Smckusick /* 112252130Smckusick * Wait a short time for disconnect. 112352130Smckusick * Don't be fooled if SII_BER happens first. 112452130Smckusick * Note: a reselect may happen here. 112552130Smckusick */ 112652130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 112752130Smckusick cstat & (SII_RST | SII_SCH), 112852130Smckusick SII_WAIT_COUNT, i); 112952130Smckusick if ((cstat & (SII_RST | SII_SCH | 113052130Smckusick SII_STATE_MSK)) != SII_SCH) { 113152130Smckusick #ifdef DEBUG 113252130Smckusick if (sii_debug > 4) 113352130Smckusick printf("cnt %d\n", i); 113452130Smckusick #endif 113552130Smckusick dstat = regs->dstat; 113652130Smckusick goto again; 113752130Smckusick } 113852130Smckusick regs->cstat = SII_SCH | SII_BER; 113952130Smckusick regs->comm = 0; 114052130Smckusick MachEmptyWriteBuffer(); 114152130Smckusick sc->sc_target = -1; 114252130Smckusick /* 114352130Smckusick * Double check that we didn't miss a state 114452130Smckusick * change between seeing it and clearing 114552130Smckusick * the SII_SCH bit. 114652130Smckusick */ 114752130Smckusick i = regs->cstat; 114852130Smckusick if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 114952130Smckusick (cstat & SII_STATE_MSK)) 115052130Smckusick sii_StateChg(sc, i); 115152130Smckusick break; 115252130Smckusick 115352130Smckusick case SCSI_MESSAGE_REJECT: 115452130Smckusick printf("sii%d: device %d: message reject.\n", 115552130Smckusick sc - sii_softc, sc->sc_target); 115652130Smckusick goto abort; 115752130Smckusick 115852130Smckusick default: 115952130Smckusick if (!(msg & SCSI_IDENTIFY)) { 116052130Smckusick printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", 116152130Smckusick sc - sii_softc, sc->sc_target, 116252130Smckusick msg); 116352130Smckusick #ifdef DEBUG 116452130Smckusick sii_DumpLog(); 116552130Smckusick #endif 116652130Smckusick break; 116752130Smckusick } 116852130Smckusick /* may want to check LUN some day */ 116952130Smckusick /* wait a short time for another msg */ 117052130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 117152130Smckusick dstat & (SII_CI | SII_DI), 117252130Smckusick SII_WAIT_COUNT, i); 117352130Smckusick if (dstat & (SII_CI | SII_DI)) { 117452130Smckusick #ifdef DEBUG 117552130Smckusick if (sii_debug > 4) 117652130Smckusick printf("cnt %d\n", i); 117752130Smckusick #endif 117852130Smckusick goto again; 117952130Smckusick } 118052130Smckusick } 118152130Smckusick break; 118252130Smckusick 118352130Smckusick case SII_MSG_OUT_PHASE: 118452130Smckusick #ifdef DEBUG 118552130Smckusick if (sii_debug > 4) 118652130Smckusick printf("MsgOut\n"); 118752130Smckusick #endif 118852130Smckusick 118952130Smckusick regs->data = SCSI_NO_OP; 119052130Smckusick regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 119152130Smckusick SII_MSG_OUT_PHASE; 119252130Smckusick MachEmptyWriteBuffer(); 119352130Smckusick 119452130Smckusick /* wait a short time for XFER complete */ 119552130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 119652130Smckusick SII_WAIT_COUNT, i); 119752130Smckusick #ifdef DEBUG 119852130Smckusick if (sii_debug > 4) 119952130Smckusick printf("ds %x i %d\n", dstat, i); 120052130Smckusick #endif 120152130Smckusick /* just clear the DNE bit and check errors later */ 120252130Smckusick if (dstat & SII_DNE) { 120352130Smckusick regs->dstat = SII_DNE; 120452130Smckusick MachEmptyWriteBuffer(); 120552130Smckusick } 120652130Smckusick break; 120752130Smckusick 120852130Smckusick default: 120952130Smckusick printf("sii%d: Couldn't handle phase %d... ignoring.\n", 121052130Smckusick sc - sii_softc, dstat & SII_PHASE_MSK); 121152130Smckusick } 121252130Smckusick } 121352130Smckusick 121452130Smckusick #ifdef DEBUG 121552130Smckusick if (sii_debug > 3) 121652130Smckusick printf("\n"); 121752130Smckusick #endif 121852130Smckusick /* 121952130Smckusick * Check to make sure we won't be interrupted again. 122052130Smckusick * Deglitch dstat register. 122152130Smckusick */ 122252130Smckusick msg = regs->dstat; 122352130Smckusick while (msg != (dstat = regs->dstat)) 122452130Smckusick msg = dstat; 122552130Smckusick if (dstat & (SII_CI | SII_DI)) 122652130Smckusick goto again; 122752130Smckusick 122852130Smckusick if (sc->sc_target < 0) { 122952130Smckusick /* look for another device that is ready */ 123052130Smckusick for (i = 0; i < SII_NCMD; i++) { 123152130Smckusick /* don't restart a disconnected command */ 123252130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 123352130Smckusick continue; 123452130Smckusick sii_StartCmd(sc, i); 123552130Smckusick break; 123652130Smckusick } 123752130Smckusick } 123852130Smckusick return; 123952130Smckusick 124052130Smckusick abort: 124152130Smckusick /* jump here to abort the current command */ 124252130Smckusick printf("sii%d: device %d: current command terminated\n", 124352130Smckusick sc - sii_softc, sc->sc_target); 124452130Smckusick #ifdef DEBUG 124552130Smckusick sii_DumpLog(); 124652130Smckusick #endif 124752130Smckusick 124852130Smckusick if ((cstat = regs->cstat) & SII_CON) { 124952130Smckusick /* try to send an abort msg for awhile */ 125052130Smckusick regs->dstat = SII_DNE; 125152130Smckusick regs->data = SCSI_ABORT; 125252130Smckusick regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 125352130Smckusick SII_MSG_OUT_PHASE; 125452130Smckusick MachEmptyWriteBuffer(); 125552130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 125652130Smckusick (dstat & (SII_DNE | SII_PHASE_MSK)) == 125752130Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 125852130Smckusick 2 * SII_WAIT_COUNT, i); 125952130Smckusick #ifdef DEBUG 126052130Smckusick if (sii_debug > 0) 126152130Smckusick printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 126252130Smckusick #endif 126352130Smckusick if (dstat & (SII_DNE | SII_PHASE_MSK) == 126452130Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) { 126552130Smckusick /* disconnect if command in progress */ 126652130Smckusick regs->comm = SII_DISCON; 126752130Smckusick MachEmptyWriteBuffer(); 126852130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 126952130Smckusick !(cstat & SII_CON), SII_WAIT_COUNT, i); 127052130Smckusick } 127152130Smckusick } else { 127252130Smckusick #ifdef DEBUG 127352130Smckusick if (sii_debug > 0) 127452130Smckusick printf("Abort: cs %x\n", cstat); 127552130Smckusick #endif 127652130Smckusick } 127752130Smckusick regs->cstat = 0xffff; 127852130Smckusick regs->dstat = 0xffff; 127952130Smckusick regs->comm = 0; 128052130Smckusick MachEmptyWriteBuffer(); 128152130Smckusick 128252130Smckusick i = sc->sc_target; 128352130Smckusick sc->sc_target = -1; 128452130Smckusick sii_CmdDone(sc, i, EIO); 128552130Smckusick #ifdef DEBUG 128652130Smckusick if (sii_debug > 4) 128752130Smckusick printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 128852130Smckusick #endif 128952130Smckusick } 129052130Smckusick 129152130Smckusick static void 129252130Smckusick sii_StateChg(sc, cstat) 129352130Smckusick register struct siisoftc *sc; 129452130Smckusick register unsigned cstat; 129552130Smckusick { 129652130Smckusick register SIIRegs *regs = sc->sc_regs; 129752130Smckusick register State *state; 129852130Smckusick register int i; 129952130Smckusick 130052130Smckusick #ifdef DEBUG 130152130Smckusick if (sii_debug > 4) 130252130Smckusick printf("SCH: "); 130352130Smckusick #endif 130452130Smckusick 130552130Smckusick switch (cstat & SII_STATE_MSK) { 130652130Smckusick case 0: 130752130Smckusick /* disconnect */ 130852130Smckusick i = sc->sc_target; 130952130Smckusick sc->sc_target = -1; 131052130Smckusick #ifdef DEBUG 131152130Smckusick if (sii_debug > 4) 131252130Smckusick printf("disconn %d ", i); 131352130Smckusick #endif 131452130Smckusick if (i >= 0 && !sc->sc_st[i].prevComm) { 131552130Smckusick printf("sii%d: device %d: spurrious disconnect (%d)\n", 131652130Smckusick sc - sii_softc, i, regs->slcsr); 131752130Smckusick sc->sc_st[i].prevComm = 0; 131852130Smckusick } 131952130Smckusick break; 132052130Smckusick 132152130Smckusick case SII_CON: 132252130Smckusick /* connected as initiator */ 132352130Smckusick i = regs->slcsr; 132452130Smckusick if (sc->sc_target == i) 132552130Smckusick break; 132652130Smckusick printf("sii%d: device %d: connect to device %d??\n", 132752130Smckusick sc - sii_softc, sc->sc_target, i); 132852130Smckusick sc->sc_target = i; 132952130Smckusick break; 133052130Smckusick 133152130Smckusick case SII_DST: 133252130Smckusick /* 133352130Smckusick * Wait for CON to become valid, 133452130Smckusick * chip is slow sometimes. 133552130Smckusick */ 133652130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 133752130Smckusick cstat & SII_CON, SII_WAIT_COUNT, i); 133852130Smckusick if (!(cstat & SII_CON)) 133952130Smckusick panic("sii resel"); 134052130Smckusick /* FALLTHROUGH */ 134152130Smckusick 134252130Smckusick case SII_CON | SII_DST: 134352130Smckusick /* 134452130Smckusick * Its a reselection. Save the ID and wait for 134552130Smckusick * interrupts to tell us what to do next 134652130Smckusick * (should be MSG_IN of IDENTIFY). 134752130Smckusick * NOTE: sc_target may be >= 0 if we were in 134852130Smckusick * the process of trying to start a command 134952130Smckusick * and were reselected before the select 135052130Smckusick * command finished. 135152130Smckusick */ 135252130Smckusick sc->sc_target = i = regs->destat; 135352130Smckusick regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 135452130Smckusick MachEmptyWriteBuffer(); 135552130Smckusick state = &sc->sc_st[i]; 135652130Smckusick if (!state->prevComm) { 135752130Smckusick printf("sii%d: device %d: spurrious reselection\n", 135852130Smckusick sc - sii_softc, i); 135952130Smckusick break; 136052130Smckusick } 136152130Smckusick state->prevComm = 0; 136252130Smckusick #ifdef DEBUG 136352130Smckusick if (sii_debug > 4) 136452130Smckusick printf("resel %d ", sc->sc_target); 136552130Smckusick #endif 136652130Smckusick break; 136752130Smckusick 136852130Smckusick #ifdef notyet 136952130Smckusick case SII_DST | SII_TGT: 137052130Smckusick case SII_CON | SII_DST | SII_TGT: 137152130Smckusick /* connected as target */ 137252130Smckusick printf("sii%d: Selected by device %d as target!!\n", 137352130Smckusick sc - sii_softc, regs->destat); 137452130Smckusick regs->comm = SII_DISCON; 137552130Smckusick MachEmptyWriteBuffer(); 137652130Smckusick SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 137752130Smckusick SII_WAIT_COUNT, i); 137852130Smckusick regs->cstat = 0xffff; 137952130Smckusick regs->dstat = 0xffff; 138052130Smckusick regs->comm = 0; 138152130Smckusick break; 138252130Smckusick #endif 138352130Smckusick 138452130Smckusick default: 138552130Smckusick printf("sii%d: Unknown state change (cs %x)!!\n", 138652130Smckusick sc - sii_softc, cstat); 138752130Smckusick #ifdef DEBUG 138852130Smckusick sii_DumpLog(); 138952130Smckusick #endif 139052130Smckusick } 139152130Smckusick } 139252130Smckusick 139352130Smckusick /* 139452130Smckusick * Read one byte of data. 139552130Smckusick */ 139652130Smckusick static int 139752130Smckusick sii_GetByte(regs, phase) 139852130Smckusick register SIIRegs *regs; 139952130Smckusick int phase; 140052130Smckusick { 140152130Smckusick register unsigned dstat; 140252130Smckusick register unsigned state; 140352130Smckusick #ifdef PROGXFER 140452130Smckusick register unsigned data; 140552130Smckusick 140652130Smckusick dstat = regs->dstat; 140752130Smckusick state = regs->cstat & SII_STATE_MSK; 140852130Smckusick regs->dmctrl = 0; 140952130Smckusick if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 141052130Smckusick regs->comm = state | phase; 141152130Smckusick MachEmptyWriteBuffer(); 141252130Smckusick /* wait a short time for IBF */ 141352130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 141452130Smckusick SII_WAIT_COUNT, i); 141552130Smckusick #ifdef DEBUG 141652130Smckusick if (!(dstat & SII_IBF)) 141752130Smckusick printf("status no IBF\n"); 141852130Smckusick #endif 141952130Smckusick } 142052130Smckusick data = regs->data; 142152130Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 142252130Smckusick printf("sii_GetByte: DNE set 5\n"); 142352130Smckusick sii_DumpLog(); 142452130Smckusick regs->dstat = SII_DNE; 142552130Smckusick } 142652130Smckusick regs->comm = SII_INXFER | state | phase; 142752130Smckusick MachEmptyWriteBuffer(); 142852130Smckusick 142952130Smckusick /* wait a short time for XFER complete */ 143052130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 143152130Smckusick SII_WAIT_COUNT, i); 143252130Smckusick 143352130Smckusick if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) { 143452130Smckusick #ifdef DEBUG 143552130Smckusick if (sii_debug > 4) 143652130Smckusick printf("cnt0 %d\n", i); 143752130Smckusick #endif 143852130Smckusick printf("MsgIn %x ?? ds %x cm %x i %d\n", 143952130Smckusick data, dstat, comm, i); /* XXX */ 144052130Smckusick sii_DumpLog(); /* XXX */ 144152130Smckusick panic("status"); /* XXX */ 144252130Smckusick goto again; 144352130Smckusick } 144452130Smckusick 144552130Smckusick /* clear the DNE, other errors handled later */ 144652130Smckusick regs->dstat = SII_DNE; 144752130Smckusick MachEmptyWriteBuffer(); 144852130Smckusick return (data); 144952130Smckusick 145052130Smckusick #else /* PROGXFER */ 145152130Smckusick register int i; 145252130Smckusick 145352130Smckusick state = regs->cstat & SII_STATE_MSK; 145452130Smckusick regs->dmctrl = 0; 145552130Smckusick if (regs->dstat & SII_DNE) { 145652130Smckusick printf("sii_GetByte: DNE cs %x ds %x cm %x\n", 145752130Smckusick regs->cstat, regs->dstat, regs->comm); /* XXX */ 145852130Smckusick regs->dstat = SII_DNE; 145952130Smckusick } 146052130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 146152130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 146252130Smckusick regs->dmlotc = 1; 146352130Smckusick regs->comm = SII_DMA | SII_INXFER | state | phase; 146452130Smckusick MachEmptyWriteBuffer(); 146552130Smckusick 146652130Smckusick /* wait a short time for XFER complete */ 146752130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 146852130Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 146952130Smckusick SII_WAIT_COUNT, i); 147052130Smckusick 147152130Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { 147252130Smckusick printf("sii_GetByte: ds %x cm %x i %d lotc %d\n", 147352130Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 147452130Smckusick sii_DumpLog(); /* XXX */ 147552130Smckusick return (-1); 147652130Smckusick } 147752130Smckusick 147852130Smckusick /* clear the DNE, other errors handled later */ 147952130Smckusick regs->dstat = SII_DNE; 148052130Smckusick MachEmptyWriteBuffer(); 148152130Smckusick 148252130Smckusick /* return one byte of data (optimized CopyFromBuffer()) */ 148352130Smckusick return (*(volatile u_short *)SII_BUF_ADDR & 0xFF); 148452130Smckusick #endif /* PROGXFER */ 148552130Smckusick } 148652130Smckusick 148752130Smckusick /* 148852130Smckusick * Exchange messages to initiate synchronous data transfers. 148952130Smckusick */ 149052130Smckusick static void 149152130Smckusick sii_DoSync(regs, state) 149252130Smckusick register SIIRegs *regs; 149352130Smckusick register State *state; 149452130Smckusick { 149552130Smckusick register unsigned dstat; 149652130Smckusick register int i; 149752130Smckusick unsigned len; 149852130Smckusick 149952130Smckusick printf("sii_DoSync: per %d req/ack %d\n", 150052130Smckusick sii_buf[3], sii_buf[4]); /* XXX */ 150152130Smckusick len = sii_buf[4]; 150252130Smckusick if (len > 3) 150352130Smckusick len = 3; /* SII chip can only handle 3 max */ 150452130Smckusick 150552130Smckusick sii_buf[0] = SCSI_EXTENDED_MSG; 150652130Smckusick sii_buf[1] = 3; /* message length */ 150752130Smckusick sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 150852130Smckusick sii_buf[4] = len; 150952130Smckusick CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 151052130Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 151152130Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 151252130Smckusick regs->dmlotc = 5; 151352130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_ATN | 151452130Smckusick (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 151552130Smckusick MachEmptyWriteBuffer(); 151652130Smckusick 151752130Smckusick /* wait a short time for XFER complete */ 151852130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 151952130Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 152052130Smckusick SII_WAIT_COUNT, i); 152152130Smckusick 152252130Smckusick if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 152352130Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 152452130Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 152552130Smckusick sii_DumpLog(); /* XXX */ 152652130Smckusick return; 152752130Smckusick } 152852130Smckusick 152952130Smckusick /* clear the DNE, other errors handled later */ 153052130Smckusick regs->dstat = SII_DNE; 153152130Smckusick regs->comm = regs->comm & SII_STATE_MSK; 153252130Smckusick MachEmptyWriteBuffer(); 153352130Smckusick 153452130Smckusick state->dmaReqAck = len; 153552130Smckusick } 153652130Smckusick 153752130Smckusick /* 153852130Smckusick * Issue the sequence of commands to the controller to start DMA. 153952130Smckusick * NOTE: the data buffer should be word-aligned for DMA out. 154052130Smckusick */ 154152130Smckusick static void 154252130Smckusick sii_StartDMA(regs, phase, dmaAddr, size) 154352130Smckusick register SIIRegs *regs; /* which SII to use */ 154452130Smckusick int phase; /* phase to send/receive data */ 154552130Smckusick u_short *dmaAddr; /* DMA buffer address */ 154652130Smckusick int size; /* # of bytes to transfer */ 154752130Smckusick { 154852130Smckusick 154952130Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 155052130Smckusick printf("sii_StartDMA: DNE set\n"); 155152130Smckusick sii_DumpLog(); 155252130Smckusick regs->dstat = SII_DNE; 155352130Smckusick } 155452130Smckusick regs->dmaddrl = ((unsigned)dmaAddr >> 1); 155552130Smckusick regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; 155652130Smckusick regs->dmlotc = size; 155752130Smckusick regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 155852130Smckusick phase; 155952130Smckusick MachEmptyWriteBuffer(); 156052130Smckusick 156152130Smckusick #ifdef DEBUG 156252130Smckusick if (sii_debug > 5) { 156352130Smckusick printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 156452130Smckusick regs->cstat, regs->dstat, regs->comm, size); 156552130Smckusick } 156652130Smckusick #endif 156752130Smckusick } 156852130Smckusick 156952130Smckusick /* 157052130Smckusick * Call the device driver's 'done' routine to let it know the command is done. 157152130Smckusick * The 'done' routine may try to start another command. 157252130Smckusick * To be fair, we should start pending commands for other devices 157352130Smckusick * before allowing the same device to start another command. 157452130Smckusick */ 157552130Smckusick static void 157652130Smckusick sii_CmdDone(sc, target, error) 157752130Smckusick register struct siisoftc *sc; /* which SII to use */ 157852130Smckusick int target; /* which device is done */ 157952130Smckusick int error; /* error code if any errors */ 158052130Smckusick { 158152130Smckusick register ScsiCmd *scsicmd; 158252130Smckusick register int i; 158352130Smckusick 158452130Smckusick scsicmd = sc->sc_cmd[target]; 158552130Smckusick #ifdef DIAGNOSTIC 158652130Smckusick if (target < 0 || !scsicmd) 158752130Smckusick panic("sii_CmdDone"); 158852130Smckusick #endif 158952130Smckusick sc->sc_cmd[target] = (ScsiCmd *)0; 159052130Smckusick #ifdef DEBUG 159152130Smckusick if (sii_debug > 1) { 159252130Smckusick printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 159352130Smckusick scsicmd->sd->sd_driver->d_name, target, 159452130Smckusick scsicmd->cmd[0], error, sc->sc_st[target].buflen); 159552130Smckusick } 159652130Smckusick #endif 159752130Smckusick 159852130Smckusick /* look for another device that is ready */ 159952130Smckusick for (i = 0; i < SII_NCMD; i++) { 160052130Smckusick /* don't restart a disconnected command */ 160152130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 160252130Smckusick continue; 160352130Smckusick sii_StartCmd(sc, i); 160452130Smckusick break; 160552130Smckusick } 160652130Smckusick 160752130Smckusick (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 160852130Smckusick sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 160952130Smckusick } 161052130Smckusick 161152130Smckusick #ifdef DEBUG 161252130Smckusick sii_DumpLog() 161352130Smckusick { 161452130Smckusick register struct sii_log *lp; 161552130Smckusick 161652130Smckusick printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 161752130Smckusick sii_debug_sz); 161852130Smckusick lp = sii_logp + 1; 161952130Smckusick if (lp > &sii_log[NLOG]) 162052130Smckusick lp = sii_log; 162152130Smckusick while (lp != sii_logp) { 162252130Smckusick printf("target %d cs %x ds %x cm %x msg %x\n", 162352130Smckusick lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); 162452130Smckusick if (++lp >= &sii_log[NLOG]) 162552130Smckusick lp = sii_log; 162652130Smckusick } 162752130Smckusick } 162852130Smckusick #endif 162952130Smckusick #endif 1630