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