156819Sralph /*- 263640Sbostic * Copyright (c) 1992, 1993 363640Sbostic * 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*67205Smckusick * @(#)sii.c 8.3 (Berkeley) 05/21/94 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 */ 65*67205Smckusick #define PARITY_ERR 0x02 /* true if parity error seen */ 6652130Smckusick 6752130Smckusick #define SII_NCMD 7 6852130Smckusick struct siisoftc { 6952130Smckusick SIIRegs *sc_regs; /* HW address of SII controller chip */ 7052130Smckusick int sc_flags; 7152130Smckusick int sc_target; /* target SCSI ID if connected */ 7252130Smckusick ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */ 7352130Smckusick State sc_st[SII_NCMD]; /* state info for each active command */ 7452130Smckusick } sii_softc[NSII]; 7552130Smckusick 7652130Smckusick /* 7752130Smckusick * MACROS for timing out spin loops. 7852130Smckusick * 7952130Smckusick * Wait until expression is true. 8052130Smckusick * 8152130Smckusick * Control register bits can change at any time so when the CPU 8252130Smckusick * reads a register, the bits might change and 8352130Smckusick * invalidate the setup and hold times for the CPU. 8452130Smckusick * This macro reads the register twice to be sure the value is stable. 8552130Smckusick * 8652130Smckusick * args: var - variable to save control register contents 8752130Smckusick * reg - control register to read 8852130Smckusick * expr - expression to spin on 8952130Smckusick * spincount - maximum number of times through the loop 9052130Smckusick * cntr - variable for number of tries 9152130Smckusick */ 9252130Smckusick #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \ 93*67205Smckusick register u_int tmp = reg; \ 9452130Smckusick for (cntr = 0; cntr < spincount; cntr++) { \ 9552130Smckusick while (tmp != (var = reg)) \ 9652130Smckusick tmp = var; \ 9752130Smckusick if (expr) \ 9852130Smckusick break; \ 9952130Smckusick if (cntr >= 100) \ 10052130Smckusick DELAY(100); \ 10152130Smckusick } \ 10252130Smckusick } 10352130Smckusick 10452130Smckusick #ifdef DEBUG 10552130Smckusick int sii_debug = 1; 10652130Smckusick int sii_debug_cmd; 10752130Smckusick int sii_debug_bn; 10852130Smckusick int sii_debug_sz; 10952130Smckusick #define NLOG 16 11052130Smckusick struct sii_log { 11152130Smckusick u_short cstat; 11252130Smckusick u_short dstat; 11352130Smckusick u_short comm; 11452130Smckusick u_short msg; 115*67205Smckusick int rlen; 116*67205Smckusick int dlen; 11752130Smckusick int target; 11852130Smckusick } sii_log[NLOG], *sii_logp = sii_log; 11952130Smckusick #endif 12052130Smckusick 12152130Smckusick u_char sii_buf[256]; /* used for extended messages */ 12252130Smckusick 12352130Smckusick #define NORESET 0 12452130Smckusick #define RESET 1 12552130Smckusick #define NOWAIT 0 12652130Smckusick #define WAIT 1 12752130Smckusick 12852130Smckusick /* define a safe address in the SCSI buffer for doing status & message DMA */ 12956819Sralph #define SII_BUF_ADDR (MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) \ 13056819Sralph + SII_MAX_DMA_XFER_LENGTH * 14) 13152130Smckusick 13256819Sralph static void sii_Reset(); 13356819Sralph static void sii_StartCmd(); 13456819Sralph static void sii_CmdDone(); 13556819Sralph static void sii_DoIntr(); 13656819Sralph static void sii_StateChg(); 13756819Sralph static void sii_DoSync(); 13856819Sralph static void sii_StartDMA(); 13956819Sralph static int sii_GetByte(); 14052130Smckusick 14152130Smckusick /* 14252130Smckusick * Test to see if device is present. 14352130Smckusick * Return true if found and initialized ok. 14452130Smckusick */ 14552130Smckusick siiprobe(cp) 14652130Smckusick register struct pmax_ctlr *cp; 14752130Smckusick { 14852130Smckusick register struct siisoftc *sc; 14952130Smckusick register int i; 15052130Smckusick 15152130Smckusick if (cp->pmax_unit >= NSII) 15252130Smckusick return (0); 15352130Smckusick sc = &sii_softc[cp->pmax_unit]; 15452130Smckusick sc->sc_regs = (SIIRegs *)cp->pmax_addr; 15552130Smckusick sc->sc_flags = cp->pmax_flags; 15652130Smckusick sc->sc_target = -1; /* no command active */ 15752130Smckusick /* 15852130Smckusick * Give each target its own DMA buffer region. 15952130Smckusick * Make it big enough for 2 max transfers so we can ping pong buffers 16052130Smckusick * while we copy the data. 16152130Smckusick */ 16252130Smckusick for (i = 0; i < SII_NCMD; i++) { 16356819Sralph sc->sc_st[i].dmaAddr[0] = (u_short *) 16456819Sralph MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) + 16552130Smckusick 2 * SII_MAX_DMA_XFER_LENGTH * i; 16652130Smckusick sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] + 16752130Smckusick SII_MAX_DMA_XFER_LENGTH; 16852130Smckusick } 16952130Smckusick 17052130Smckusick printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr); 17152130Smckusick sii_Reset(sc->sc_regs, RESET); 17252130Smckusick return (1); 17352130Smckusick } 17452130Smckusick 17552130Smckusick /* 17652130Smckusick * Start activity on a SCSI device. 17752130Smckusick * We maintain information on each device separately since devices can 17852130Smckusick * connect/disconnect during an operation. 17952130Smckusick */ 18052130Smckusick void 18152130Smckusick siistart(scsicmd) 18252130Smckusick register ScsiCmd *scsicmd; /* command to start */ 18352130Smckusick { 18452130Smckusick register struct scsi_device *sdp = scsicmd->sd; 18552130Smckusick register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr]; 18652130Smckusick int s; 18752130Smckusick 18852130Smckusick s = splbio(); 18952130Smckusick /* 19052130Smckusick * Check if another command is already in progress. 19152130Smckusick * We may have to change this if we allow SCSI devices with 19252130Smckusick * separate LUNs. 19352130Smckusick */ 19452130Smckusick if (sc->sc_cmd[sdp->sd_drive]) { 19552130Smckusick printf("sii%d: device %s busy at start\n", sdp->sd_ctlr, 19652130Smckusick sdp->sd_driver->d_name); 19752130Smckusick (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 19852130Smckusick scsicmd->buflen, 0); 19952130Smckusick splx(s); 20052130Smckusick } 20152130Smckusick sc->sc_cmd[sdp->sd_drive] = scsicmd; 20252130Smckusick sii_StartCmd(sc, sdp->sd_drive); 20352130Smckusick splx(s); 20452130Smckusick } 20552130Smckusick 20652130Smckusick /* 20752130Smckusick * Check to see if any SII chips have pending interrupts 20852130Smckusick * and process as appropriate. 20952130Smckusick */ 21052130Smckusick void 21152697Sralph siiintr(unit) 21252697Sralph int unit; 21352130Smckusick { 21452697Sralph register struct siisoftc *sc = &sii_softc[unit]; 215*67205Smckusick u_int dstat; 21652130Smckusick 21752130Smckusick /* 21852130Smckusick * Find which controller caused the interrupt. 21952130Smckusick */ 22052697Sralph dstat = sc->sc_regs->dstat; 22152697Sralph if (dstat & (SII_CI | SII_DI)) 22252697Sralph sii_DoIntr(sc, dstat); 22352130Smckusick } 22452130Smckusick 22552130Smckusick /* 22652130Smckusick * Reset the SII chip and do a SCSI reset if 'reset' is true. 22752130Smckusick * NOTE: if !cold && reset, should probably probe for devices 22852130Smckusick * since a SCSI bus reset will set UNIT_ATTENTION. 22952130Smckusick */ 23052130Smckusick static void 23152130Smckusick sii_Reset(regs, reset) 23252130Smckusick register SIIRegs *regs; 23352130Smckusick int reset; /* TRUE => reset SCSI bus */ 23452130Smckusick { 23552130Smckusick 23652130Smckusick #ifdef DEBUG 23752130Smckusick if (sii_debug > 1) 23852130Smckusick printf("sii: RESET\n"); 23952130Smckusick #endif 24052130Smckusick /* 24152130Smckusick * Reset the SII chip. 24252130Smckusick */ 24352130Smckusick regs->comm = SII_CHRESET; 24452130Smckusick /* 24552130Smckusick * Set arbitrated bus mode. 24652130Smckusick */ 24752130Smckusick regs->csr = SII_HPM; 24852130Smckusick /* 24952130Smckusick * SII is always ID 7. 25052130Smckusick */ 25152130Smckusick regs->id = SII_ID_IO | 7; 25252130Smckusick /* 25352130Smckusick * Enable SII to drive the SCSI bus. 25452130Smckusick */ 25552130Smckusick regs->dictrl = SII_PRE; 25652130Smckusick regs->dmctrl = 0; 25752130Smckusick 25852130Smckusick if (reset) { 25952130Smckusick register int i; 26052130Smckusick 26152130Smckusick /* 26252130Smckusick * Assert SCSI bus reset for at least 25 Usec to clear the 26352130Smckusick * world. SII_DO_RST is self clearing. 26452130Smckusick * Delay 250 ms before doing any commands. 26552130Smckusick */ 26652130Smckusick regs->comm = SII_DO_RST; 26752130Smckusick MachEmptyWriteBuffer(); 26852130Smckusick DELAY(250000); 26952130Smckusick 27052130Smckusick /* rearbitrate synchronous offset */ 27152130Smckusick for (i = 0; i < SII_NCMD; i++) 27252130Smckusick sii_softc[0].sc_st[i].dmaReqAck = 0; 27352130Smckusick } 27452130Smckusick 27552130Smckusick /* 27652130Smckusick * Clear any pending interrupts from the reset. 27752130Smckusick */ 27852130Smckusick regs->cstat = regs->cstat; 27952130Smckusick regs->dstat = regs->dstat; 28052130Smckusick /* 28152130Smckusick * Set up SII for arbitrated bus mode, SCSI parity checking, 28252130Smckusick * Reselect Enable, and Interrupt Enable. 28352130Smckusick */ 28452130Smckusick regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE; 28552130Smckusick MachEmptyWriteBuffer(); 28652130Smckusick } 28752130Smckusick 28852130Smckusick /* 28952130Smckusick * Start a SCSI command by sending the cmd data 29052130Smckusick * to a SCSI controller via the SII. 29152130Smckusick * Call the device done proceedure if it can't be started. 29252130Smckusick * NOTE: we should be called with interrupts disabled. 29352130Smckusick */ 29452130Smckusick static void 29552130Smckusick sii_StartCmd(sc, target) 29652130Smckusick register struct siisoftc *sc; /* which SII to use */ 29752130Smckusick register int target; /* which command to start */ 29852130Smckusick { 29952130Smckusick register SIIRegs *regs; 30052130Smckusick register ScsiCmd *scsicmd; 30152130Smckusick register State *state; 302*67205Smckusick register u_int status; 30352130Smckusick int error, retval; 30452130Smckusick 30552130Smckusick /* if another command is currently in progress, just wait */ 30652130Smckusick if (sc->sc_target >= 0) 30752130Smckusick return; 30852130Smckusick 30952130Smckusick /* initialize state information for this command */ 31052130Smckusick scsicmd = sc->sc_cmd[target]; 31152130Smckusick state = &sc->sc_st[target]; 31252130Smckusick state->flags = FIRST_DMA; 31352130Smckusick state->prevComm = 0; 31452130Smckusick state->dmalen = 0; 31552130Smckusick state->dmaCurPhase = -1; 31652130Smckusick state->dmaPrevPhase = -1; 31752130Smckusick state->dmaBufIndex = 0; 31852130Smckusick state->cmd = scsicmd->cmd; 31952130Smckusick state->cmdlen = scsicmd->cmdlen; 32052130Smckusick if ((state->buflen = scsicmd->buflen) == 0) { 32152130Smckusick state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */ 32252130Smckusick state->buf = (char *)0; 32352130Smckusick } else { 32452130Smckusick state->dmaDataPhase = 32552130Smckusick (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ? 32652130Smckusick SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE; 32752130Smckusick state->buf = scsicmd->buf; 32852130Smckusick } 32952130Smckusick 33052130Smckusick #ifdef DEBUG 33152130Smckusick if (sii_debug > 1) { 33252130Smckusick printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 33352130Smckusick scsicmd->sd->sd_driver->d_name, target, 33452130Smckusick scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 33552130Smckusick state->dmaDataPhase); 33652130Smckusick } 33752130Smckusick sii_debug_cmd = scsicmd->cmd[0]; 338*67205Smckusick if (scsicmd->cmd[0] == SCSI_READ_EXT || 339*67205Smckusick scsicmd->cmd[0] == SCSI_WRITE_EXT) { 34052130Smckusick sii_debug_bn = (scsicmd->cmd[2] << 24) | 34152130Smckusick (scsicmd->cmd[3] << 16) | 34252130Smckusick (scsicmd->cmd[4] << 8) | 34352130Smckusick scsicmd->cmd[5]; 34452130Smckusick sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 345*67205Smckusick } else { 346*67205Smckusick sii_debug_bn = 0; 347*67205Smckusick sii_debug_sz = 0; 34852130Smckusick } 34952130Smckusick #endif 35052130Smckusick 35152130Smckusick /* try to select the target */ 35252130Smckusick regs = sc->sc_regs; 35352130Smckusick 35452130Smckusick /* 35552130Smckusick * Another device may have selected us; in which case, 35652130Smckusick * this command will be restarted later. 35752130Smckusick */ 35852130Smckusick if ((status = regs->dstat) & (SII_CI | SII_DI)) { 35952130Smckusick sii_DoIntr(sc, status); 36052130Smckusick return; 36152130Smckusick } 36252130Smckusick 36352130Smckusick sc->sc_target = target; 364*67205Smckusick #if 0 365*67205Smckusick /* seem to have problems with synchronous transfers */ 36652130Smckusick if (scsicmd->flags & SCSICMD_USE_SYNC) { 36752130Smckusick printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 36852130Smckusick /* 36952130Smckusick * Setup to send both the identify message and the synchronous 37052130Smckusick * data transfer request. 37152130Smckusick */ 37252130Smckusick sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 37352130Smckusick sii_buf[1] = SCSI_EXTENDED_MSG; 37452130Smckusick sii_buf[2] = 3; /* message length */ 37552130Smckusick sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 37652130Smckusick sii_buf[4] = 0; 37752130Smckusick sii_buf[5] = 3; /* maximum SII chip supports */ 37852130Smckusick 37952130Smckusick state->dmaCurPhase = SII_MSG_OUT_PHASE, 38052130Smckusick state->dmalen = 6; 38152130Smckusick CopyToBuffer((u_short *)sii_buf, 38252130Smckusick (volatile u_short *)SII_BUF_ADDR, 6); 38352130Smckusick regs->slcsr = target; 384*67205Smckusick regs->dmctrl = state->dmaReqAck; 385*67205Smckusick regs->dmaddrl = (u_short)(SII_BUF_ADDR >> 1); 386*67205Smckusick regs->dmaddrh = (u_short)(SII_BUF_ADDR >> 17) & 03; 38752130Smckusick regs->dmlotc = 6; 38852130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 38952130Smckusick SII_CON | SII_MSG_OUT_PHASE; 390*67205Smckusick } else 391*67205Smckusick #endif 392*67205Smckusick { 39352130Smckusick /* do a chained, select with ATN and programmed I/O command */ 39452130Smckusick regs->data = SCSI_DIS_REC_IDENTIFY; 39552130Smckusick regs->slcsr = target; 396*67205Smckusick regs->dmctrl = state->dmaReqAck; 39752130Smckusick regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 39852130Smckusick SII_MSG_OUT_PHASE; 39952130Smckusick } 40052130Smckusick MachEmptyWriteBuffer(); 40152130Smckusick 40252130Smckusick /* 40352130Smckusick * Wait for something to happen 40452130Smckusick * (should happen soon or we would use interrupts). 40552130Smckusick */ 40652130Smckusick SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 40753085Sralph SII_WAIT_COUNT/4, retval); 40852130Smckusick 40952130Smckusick /* check to see if we are connected OK */ 41052130Smckusick if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 41152130Smckusick (SII_SCH | SII_CON)) { 41252130Smckusick regs->cstat = status; 41352130Smckusick MachEmptyWriteBuffer(); 41452130Smckusick 41552130Smckusick #ifdef DEBUG 41652130Smckusick sii_logp->target = target; 41752130Smckusick sii_logp->cstat = status; 41852130Smckusick sii_logp->dstat = 0; 41952130Smckusick sii_logp->comm = regs->comm; 42052130Smckusick sii_logp->msg = -1; 421*67205Smckusick sii_logp->rlen = state->buflen; 422*67205Smckusick sii_logp->dlen = state->dmalen; 42352130Smckusick if (++sii_logp >= &sii_log[NLOG]) 42452130Smckusick sii_logp = sii_log; 42552130Smckusick #endif 42652130Smckusick 42752130Smckusick /* wait a short time for command phase */ 42852130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 42952130Smckusick SII_WAIT_COUNT, retval); 43052130Smckusick #ifdef DEBUG 43152130Smckusick if (sii_debug > 2) 43252130Smckusick printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 43352130Smckusick #endif 43452130Smckusick if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 43552130Smckusick (SII_MIS | SII_CMD_PHASE)) { 43652130Smckusick printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 43752130Smckusick regs->cstat, status, retval); /* XXX */ 43852130Smckusick /* process interrupt or continue until it happens */ 43952130Smckusick if (status & (SII_CI | SII_DI)) 44052130Smckusick sii_DoIntr(sc, status); 44152130Smckusick return; 44252130Smckusick } 44352130Smckusick regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 44452130Smckusick 44552130Smckusick /* send command data */ 44652130Smckusick CopyToBuffer((u_short *)state->cmd, 44752130Smckusick (volatile u_short *)state->dmaAddr[0], state->cmdlen); 44852130Smckusick sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 44952130Smckusick state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 45052130Smckusick 45152130Smckusick /* wait a little while for DMA to finish */ 45252130Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 45352130Smckusick SII_WAIT_COUNT, retval); 45452130Smckusick #ifdef DEBUG 45552130Smckusick if (sii_debug > 2) 45652130Smckusick printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 45752130Smckusick #endif 45852130Smckusick if (status & (SII_CI | SII_DI)) 45952130Smckusick sii_DoIntr(sc, status); 46052130Smckusick #ifdef DEBUG 46152130Smckusick if (sii_debug > 2) 46252130Smckusick printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 46352130Smckusick #endif 46452130Smckusick return; 46552130Smckusick } 46652130Smckusick 46752130Smckusick /* 46852130Smckusick * Another device may have selected us; in which case, 46952130Smckusick * this command will be restarted later. 47052130Smckusick */ 47152130Smckusick if (status & (SII_CI | SII_DI)) { 47252130Smckusick sii_DoIntr(sc, regs->dstat); 47352130Smckusick return; 47452130Smckusick } 47552130Smckusick 47652130Smckusick /* 47752130Smckusick * Disconnect if selection command still in progress. 47852130Smckusick */ 47952130Smckusick if (status & SII_SIP) { 48052130Smckusick error = ENXIO; /* device didn't respond */ 48152130Smckusick regs->comm = SII_DISCON; 48252130Smckusick MachEmptyWriteBuffer(); 48352130Smckusick SII_WAIT_UNTIL(status, regs->cstat, 48452130Smckusick !(status & (SII_CON | SII_SIP)), 48552130Smckusick SII_WAIT_COUNT, retval); 48652130Smckusick } else 48752130Smckusick error = EBUSY; /* couldn't get the bus */ 48852130Smckusick #ifdef DEBUG 48953085Sralph if (sii_debug > 1) 49052130Smckusick printf("sii_StartCmd: Couldn't select target %d error %d\n", 49152130Smckusick target, error); 49252130Smckusick #endif 49352130Smckusick sc->sc_target = -1; 49452130Smckusick regs->cstat = 0xffff; 49552130Smckusick regs->dstat = 0xffff; 49652130Smckusick regs->comm = 0; 49752130Smckusick MachEmptyWriteBuffer(); 49852130Smckusick sii_CmdDone(sc, target, error); 49952130Smckusick } 50052130Smckusick 50152130Smckusick /* 50252130Smckusick * Process interrupt conditions. 50352130Smckusick */ 50452130Smckusick static void 50552130Smckusick sii_DoIntr(sc, dstat) 50652130Smckusick register struct siisoftc *sc; 507*67205Smckusick register u_int dstat; 50852130Smckusick { 50952130Smckusick register SIIRegs *regs = sc->sc_regs; 51052130Smckusick register State *state; 511*67205Smckusick register u_int cstat; 512*67205Smckusick int i, msg; 513*67205Smckusick u_int comm; 51452130Smckusick 51552130Smckusick again: 51652130Smckusick comm = regs->comm; 51752130Smckusick 51852130Smckusick #ifdef DEBUG 51952130Smckusick if (sii_debug > 3) 52052130Smckusick printf("sii_DoIntr: cs %x, ds %x cm %x ", 52152130Smckusick regs->cstat, dstat, comm); 52252130Smckusick sii_logp->target = sc->sc_target; 52352130Smckusick sii_logp->cstat = regs->cstat; 52452130Smckusick sii_logp->dstat = dstat; 52552130Smckusick sii_logp->comm = comm; 52652130Smckusick sii_logp->msg = -1; 527*67205Smckusick if (sc->sc_target >= 0) { 528*67205Smckusick sii_logp->rlen = sc->sc_st[sc->sc_target].buflen; 529*67205Smckusick sii_logp->dlen = sc->sc_st[sc->sc_target].dmalen; 530*67205Smckusick } else { 531*67205Smckusick sii_logp->rlen = 0; 532*67205Smckusick sii_logp->dlen = 0; 533*67205Smckusick } 53452130Smckusick if (++sii_logp >= &sii_log[NLOG]) 53552130Smckusick sii_logp = sii_log; 53652130Smckusick #endif 53752130Smckusick 53852130Smckusick regs->dstat = dstat; /* acknowledge everything */ 53952130Smckusick MachEmptyWriteBuffer(); 54052130Smckusick 54152130Smckusick if (dstat & SII_CI) { 54252130Smckusick /* deglitch cstat register */ 54352130Smckusick msg = regs->cstat; 54452130Smckusick while (msg != (cstat = regs->cstat)) 54552130Smckusick msg = cstat; 54652130Smckusick regs->cstat = cstat; /* acknowledge everything */ 54752130Smckusick MachEmptyWriteBuffer(); 54852130Smckusick #ifdef DEBUG 54952130Smckusick if (sii_logp > sii_log) 55052130Smckusick sii_logp[-1].cstat = cstat; 55152130Smckusick else 55252130Smckusick sii_log[NLOG - 1].cstat = cstat; 55352130Smckusick #endif 55452130Smckusick 55552130Smckusick /* check for a BUS RESET */ 55652130Smckusick if (cstat & SII_RST) { 55752130Smckusick printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 55852130Smckusick /* need to flush disconnected commands */ 55952697Sralph for (i = 0; i < SII_NCMD; i++) { 56052697Sralph if (!sc->sc_cmd[i]) 56152697Sralph continue; 56252130Smckusick sii_CmdDone(sc, i, EIO); 56352697Sralph } 56452130Smckusick /* rearbitrate synchronous offset */ 56552130Smckusick for (i = 0; i < SII_NCMD; i++) 56652130Smckusick sc->sc_st[i].dmaReqAck = 0; 56752130Smckusick sc->sc_target = -1; 56852130Smckusick return; 56952130Smckusick } 57052130Smckusick 57152130Smckusick #ifdef notdef 57252130Smckusick /* 57352130Smckusick * Check for a BUS ERROR. 57452130Smckusick * According to DEC, this feature doesn't really work 57552130Smckusick * and to just clear the bit if it's set. 57652130Smckusick */ 57752130Smckusick if (cstat & SII_BER) { 57852130Smckusick } 57952130Smckusick #endif 58052130Smckusick 58152130Smckusick /* check for state change */ 58252130Smckusick if (cstat & SII_SCH) { 58352130Smckusick sii_StateChg(sc, cstat); 58452130Smckusick comm = regs->comm; 58552130Smckusick } 58652130Smckusick } 58752130Smckusick 58852130Smckusick /* check for DMA completion */ 58952130Smckusick if (dstat & SII_DNE) { 59052130Smckusick u_short *dma; 59152130Smckusick char *buf; 59252130Smckusick 59352130Smckusick /* 59452130Smckusick * There is a race condition with SII_SCH. There is a short 59552130Smckusick * window between the time a SII_SCH is seen after a disconnect 59652130Smckusick * and when the SII_SCH is cleared. A reselect can happen 59752130Smckusick * in this window and we will clear the SII_SCH without 59852130Smckusick * processing the reconnect. 59952130Smckusick */ 60052130Smckusick if (sc->sc_target < 0) { 60152130Smckusick cstat = regs->cstat; 60252130Smckusick printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 60352130Smckusick sc - sii_softc, sc->sc_target, 60452130Smckusick regs->slcsr, regs->destat, 60552130Smckusick cstat); /* XXX */ 60652130Smckusick if (cstat & SII_DST) { 60752130Smckusick sc->sc_target = regs->destat; 60852130Smckusick state->prevComm = 0; 60952130Smckusick } else 61052130Smckusick panic("sc_target 1"); 61152130Smckusick } 61252130Smckusick state = &sc->sc_st[sc->sc_target]; 613*67205Smckusick /* check for a PARITY ERROR */ 614*67205Smckusick if (dstat & SII_IPE) { 615*67205Smckusick state->flags |= PARITY_ERR; 616*67205Smckusick printf("sii%d: Parity error!!\n", sc - sii_softc); 617*67205Smckusick goto abort; 618*67205Smckusick } 61952130Smckusick /* dmalen = amount left to transfer, i = amount transfered */ 62052130Smckusick i = state->dmalen; 62152130Smckusick state->dmalen = 0; 62252130Smckusick state->dmaCurPhase = -1; 62352130Smckusick #ifdef DEBUG 62452130Smckusick if (sii_debug > 4) { 62552130Smckusick printf("DNE: amt %d ", i); 62652130Smckusick if (!(dstat & SII_TCZ)) 62752130Smckusick printf("no TCZ?? (%d) ", regs->dmlotc); 62852130Smckusick } else if (!(dstat & SII_TCZ)) { 62952130Smckusick printf("sii%d: device %d: no TCZ?? (%d)\n", 63052130Smckusick sc - sii_softc, sc->sc_target, regs->dmlotc); 63152130Smckusick sii_DumpLog(); /* XXX */ 63252130Smckusick } 63352130Smckusick #endif 63452130Smckusick switch (comm & SII_PHASE_MSK) { 63552130Smckusick case SII_CMD_PHASE: 63652130Smckusick state->cmdlen -= i; 63752130Smckusick break; 63852130Smckusick 63952130Smckusick case SII_DATA_IN_PHASE: 64052130Smckusick /* check for more data for the same phase */ 64152130Smckusick dma = state->dmaAddr[state->dmaBufIndex]; 64252130Smckusick buf = state->buf; 64352130Smckusick state->buf += i; 64452130Smckusick state->buflen -= i; 64552130Smckusick if (state->buflen > 0 && !(dstat & SII_MIS)) { 64652130Smckusick int len; 64752130Smckusick 64852130Smckusick /* start reading next chunk */ 64952130Smckusick len = state->buflen; 65052130Smckusick if (len > SII_MAX_DMA_XFER_LENGTH) 65152130Smckusick len = SII_MAX_DMA_XFER_LENGTH; 65252130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 65352130Smckusick sii_StartDMA(regs, 65452130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 65552130Smckusick state->dmaAddr[state->dmaBufIndex], 65652130Smckusick state->dmalen = len); 65752130Smckusick dstat &= ~(SII_IBF | SII_TBE); 65852130Smckusick } 65952130Smckusick /* copy in the data */ 66052130Smckusick CopyFromBuffer((volatile u_short *)dma, buf, i); 66152130Smckusick break; 66252130Smckusick 66352130Smckusick case SII_DATA_OUT_PHASE: 66452130Smckusick state->dmaBufIndex = !state->dmaBufIndex; 66552130Smckusick state->buf += i; 66652130Smckusick state->buflen -= i; 66752130Smckusick 66852130Smckusick /* check for more data for the same phase */ 66952130Smckusick if (state->buflen <= 0 || (dstat & SII_MIS)) 67052130Smckusick break; 67152130Smckusick 67252130Smckusick /* start next chunk */ 67352130Smckusick i = state->buflen; 67452130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) { 67552130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 67652130Smckusick SII_DATA_OUT_PHASE, 67752130Smckusick state->dmaAddr[state->dmaBufIndex], 67852130Smckusick state->dmalen = 67952130Smckusick SII_MAX_DMA_XFER_LENGTH); 68052130Smckusick /* prepare for next chunk */ 68152130Smckusick i -= SII_MAX_DMA_XFER_LENGTH; 68252130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 68352130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 68452130Smckusick CopyToBuffer((u_short *)(state->buf + 68552130Smckusick SII_MAX_DMA_XFER_LENGTH), 68652130Smckusick (volatile u_short *) 68752130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 68852130Smckusick } else { 68952130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 69052130Smckusick SII_DATA_OUT_PHASE, 69152130Smckusick state->dmaAddr[state->dmaBufIndex], 69252130Smckusick state->dmalen = i); 69352130Smckusick } 69452130Smckusick dstat &= ~(SII_IBF | SII_TBE); 69552130Smckusick } 69652130Smckusick } 69752130Smckusick 69852130Smckusick /* check for phase change or another MsgIn/Out */ 69952130Smckusick if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 70052130Smckusick /* 70152130Smckusick * There is a race condition with SII_SCH. There is a short 70252130Smckusick * window between the time a SII_SCH is seen after a disconnect 70352130Smckusick * and when the SII_SCH is cleared. A reselect can happen 70452130Smckusick * in this window and we will clear the SII_SCH without 70552130Smckusick * processing the reconnect. 70652130Smckusick */ 70752130Smckusick if (sc->sc_target < 0) { 70852130Smckusick cstat = regs->cstat; 70952130Smckusick printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 71052130Smckusick sc - sii_softc, sc->sc_target, 71152130Smckusick regs->slcsr, regs->destat, 71252130Smckusick cstat, dstat); /* XXX */ 71352130Smckusick if (cstat & SII_DST) { 71452130Smckusick sc->sc_target = regs->destat; 71552130Smckusick state->prevComm = 0; 716*67205Smckusick } else { 717*67205Smckusick sii_DumpLog(); 71852130Smckusick panic("sc_target 2"); 719*67205Smckusick } 72052130Smckusick } 72152130Smckusick state = &sc->sc_st[sc->sc_target]; 72252130Smckusick switch (dstat & SII_PHASE_MSK) { 72352130Smckusick case SII_CMD_PHASE: 72452130Smckusick if (state->dmaPrevPhase >= 0) { 72552130Smckusick /* restart DMA after disconnect/reconnect */ 72652130Smckusick if (state->dmaPrevPhase != SII_CMD_PHASE) { 72752130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 72852130Smckusick sc - sii_softc, sc->sc_target); 72952130Smckusick goto abort; 73052130Smckusick } 73152130Smckusick state->dmaCurPhase = SII_CMD_PHASE; 73252130Smckusick state->dmaPrevPhase = -1; 73352130Smckusick regs->dmaddrl = state->dmaAddrL; 73452130Smckusick regs->dmaddrh = state->dmaAddrH; 73552130Smckusick regs->dmlotc = state->dmaCnt; 73652130Smckusick if (state->dmaCnt & 1) 73752130Smckusick regs->dmabyte = state->dmaByte; 73852130Smckusick regs->comm = SII_DMA | SII_INXFER | 73952130Smckusick (comm & SII_STATE_MSK) | SII_CMD_PHASE; 74052130Smckusick MachEmptyWriteBuffer(); 74152130Smckusick #ifdef DEBUG 74252130Smckusick if (sii_debug > 4) 74352130Smckusick printf("Cmd dcnt %d dadr %x ", 74452130Smckusick state->dmaCnt, 74552130Smckusick (state->dmaAddrH << 16) | 74652130Smckusick state->dmaAddrL); 74752130Smckusick #endif 74852130Smckusick } else { 74952130Smckusick /* send command data */ 75052130Smckusick i = state->cmdlen; 75152130Smckusick if (i == 0) { 75252130Smckusick printf("sii%d: device %d: cmd count exceeded\n", 75352130Smckusick sc - sii_softc, sc->sc_target); 75452130Smckusick goto abort; 75552130Smckusick } 75652130Smckusick CopyToBuffer((u_short *)state->cmd, 75752130Smckusick (volatile u_short *)state->dmaAddr[0], 75852130Smckusick i); 75952130Smckusick sii_StartDMA(regs, state->dmaCurPhase = 76052130Smckusick SII_CMD_PHASE, state->dmaAddr[0], 76152130Smckusick state->dmalen = i); 76252130Smckusick } 76352130Smckusick /* wait a short time for XFER complete */ 76452130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 76552130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 76652130Smckusick if (dstat & (SII_CI | SII_DI)) { 76752130Smckusick #ifdef DEBUG 76852130Smckusick if (sii_debug > 4) 76952130Smckusick printf("cnt %d\n", i); 77052130Smckusick else if (sii_debug > 0) 77152130Smckusick printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 77252130Smckusick dstat, i); 77352130Smckusick #endif 77452130Smckusick goto again; 77552130Smckusick } 77652130Smckusick break; 77752130Smckusick 77852130Smckusick case SII_DATA_IN_PHASE: 77952130Smckusick case SII_DATA_OUT_PHASE: 78052130Smckusick if (state->cmdlen > 0) { 78152130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 78252130Smckusick sc - sii_softc, sc->sc_target, 78352130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 78452130Smckusick state->cmdlen); 78552130Smckusick state->cmdlen = 0; 78652130Smckusick #ifdef DEBUG 78752130Smckusick sii_DumpLog(); 78852130Smckusick #endif 78952130Smckusick } 79052130Smckusick if (state->dmaPrevPhase >= 0) { 79152130Smckusick /* restart DMA after disconnect/reconnect */ 79252130Smckusick if (state->dmaPrevPhase != 79352130Smckusick (dstat & SII_PHASE_MSK)) { 79452130Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 79552130Smckusick sc - sii_softc, sc->sc_target); 79652130Smckusick goto abort; 79752130Smckusick } 79852130Smckusick state->dmaCurPhase = state->dmaPrevPhase; 79952130Smckusick state->dmaPrevPhase = -1; 80052130Smckusick regs->dmaddrl = state->dmaAddrL; 80152130Smckusick regs->dmaddrh = state->dmaAddrH; 80252130Smckusick regs->dmlotc = state->dmaCnt; 80352130Smckusick if (state->dmaCnt & 1) 80452130Smckusick regs->dmabyte = state->dmaByte; 80552130Smckusick regs->comm = SII_DMA | SII_INXFER | 80652130Smckusick (comm & SII_STATE_MSK) | 80752130Smckusick state->dmaCurPhase; 80852130Smckusick MachEmptyWriteBuffer(); 80952130Smckusick #ifdef DEBUG 81052130Smckusick if (sii_debug > 4) 81152130Smckusick printf("Data %d dcnt %d dadr %x ", 81252130Smckusick state->dmaDataPhase, 81352130Smckusick state->dmaCnt, 81452130Smckusick (state->dmaAddrH << 16) | 81552130Smckusick state->dmaAddrL); 81652130Smckusick #endif 81752130Smckusick break; 81852130Smckusick } 81952130Smckusick if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 82052130Smckusick printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 82152130Smckusick sc - sii_softc, sc->sc_target, 82252130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0]); 82352130Smckusick goto abort; 82452130Smckusick } 82552130Smckusick #ifdef DEBUG 82652130Smckusick if (sii_debug > 4) { 82752130Smckusick printf("Data %d ", state->dmaDataPhase); 82852130Smckusick if (sii_debug > 5) 82952130Smckusick printf("\n"); 83052130Smckusick } 83152130Smckusick #endif 83252130Smckusick i = state->buflen; 83352130Smckusick if (i == 0) { 83452130Smckusick printf("sii%d: device %d: data count exceeded\n", 83552130Smckusick sc - sii_softc, sc->sc_target); 83652130Smckusick goto abort; 83752130Smckusick } 83852130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 83952130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 84052130Smckusick if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 84152130Smckusick sii_StartDMA(regs, 84252130Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 84352130Smckusick state->dmaAddr[state->dmaBufIndex], 84452130Smckusick state->dmalen = i); 84552130Smckusick break; 84652130Smckusick } 84752130Smckusick /* start first chunk */ 84852130Smckusick if (state->flags & FIRST_DMA) { 84952130Smckusick state->flags &= ~FIRST_DMA; 85052130Smckusick CopyToBuffer((u_short *)state->buf, 85152130Smckusick (volatile u_short *) 85252130Smckusick state->dmaAddr[state->dmaBufIndex], i); 85352130Smckusick } 85452130Smckusick sii_StartDMA(regs, 85552130Smckusick state->dmaCurPhase = SII_DATA_OUT_PHASE, 85652130Smckusick state->dmaAddr[state->dmaBufIndex], 85752130Smckusick state->dmalen = i); 85852130Smckusick i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 85952130Smckusick if (i > 0) { 86052130Smckusick /* prepare for next chunk */ 86152130Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 86252130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 86352130Smckusick CopyToBuffer((u_short *)(state->buf + 86452130Smckusick SII_MAX_DMA_XFER_LENGTH), 86552130Smckusick (volatile u_short *) 86652130Smckusick state->dmaAddr[!state->dmaBufIndex], i); 86752130Smckusick } 86852130Smckusick break; 86952130Smckusick 87052130Smckusick case SII_STATUS_PHASE: 87152130Smckusick if (state->cmdlen > 0) { 87252130Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 87352130Smckusick sc - sii_softc, sc->sc_target, 87452130Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 87552130Smckusick state->cmdlen); 87652130Smckusick state->cmdlen = 0; 87752130Smckusick #ifdef DEBUG 87852130Smckusick sii_DumpLog(); 87952130Smckusick #endif 88052130Smckusick } 88152130Smckusick 88252130Smckusick /* read amount transfered if DMA didn't finish */ 88352130Smckusick if (state->dmalen > 0) { 88452130Smckusick i = state->dmalen - regs->dmlotc; 88552130Smckusick state->dmalen = 0; 88652130Smckusick state->dmaCurPhase = -1; 88752130Smckusick regs->dmlotc = 0; 88852130Smckusick regs->comm = comm & 88952130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 89052130Smckusick MachEmptyWriteBuffer(); 89152130Smckusick regs->dstat = SII_DNE; 89252130Smckusick MachEmptyWriteBuffer(); 89352130Smckusick #ifdef DEBUG 89452130Smckusick if (sii_debug > 4) 89552130Smckusick printf("DMA amt %d ", i); 89652130Smckusick #endif 89752130Smckusick switch (comm & SII_PHASE_MSK) { 89852130Smckusick case SII_DATA_IN_PHASE: 89952130Smckusick /* copy in the data */ 90052130Smckusick CopyFromBuffer((volatile u_short *) 90152130Smckusick state->dmaAddr[state->dmaBufIndex], 90252130Smckusick state->buf, i); 90352130Smckusick 90452130Smckusick case SII_CMD_PHASE: 90552130Smckusick case SII_DATA_OUT_PHASE: 90652130Smckusick state->buflen -= i; 90752130Smckusick } 90852130Smckusick } 90952130Smckusick 91052130Smckusick /* read a one byte status message */ 91152130Smckusick state->statusByte = msg = 912*67205Smckusick sii_GetByte(regs, SII_STATUS_PHASE, 1); 91352130Smckusick if (msg < 0) { 91452130Smckusick dstat = regs->dstat; 91552130Smckusick goto again; 91652130Smckusick } 91752130Smckusick #ifdef DEBUG 91852130Smckusick if (sii_debug > 4) 91952130Smckusick printf("Status %x ", msg); 92052130Smckusick if (sii_logp > sii_log) 92152130Smckusick sii_logp[-1].msg = msg; 92252130Smckusick else 92352130Smckusick sii_log[NLOG - 1].msg = msg; 92452130Smckusick #endif 92552130Smckusick 92652130Smckusick /* do a quick wait for COMMAND_COMPLETE */ 92752130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 92852130Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 92952130Smckusick if (dstat & (SII_CI | SII_DI)) { 93052130Smckusick #ifdef DEBUG 93152130Smckusick if (sii_debug > 4) 93252130Smckusick printf("cnt2 %d\n", i); 93352130Smckusick #endif 93452130Smckusick goto again; 93552130Smckusick } 93652130Smckusick break; 93752130Smckusick 93852130Smckusick case SII_MSG_IN_PHASE: 93952130Smckusick /* 94052130Smckusick * Save DMA state if DMA didn't finish. 94152130Smckusick * Be careful not to save state again after reconnect 94252130Smckusick * and see RESTORE_POINTER message. 94352130Smckusick * Note that the SII DMA address is not incremented 94452130Smckusick * as DMA proceeds. 94552130Smckusick */ 94652130Smckusick if (state->dmaCurPhase > 0) { 94752130Smckusick /* save dma registers */ 94852130Smckusick state->dmaPrevPhase = state->dmaCurPhase; 94952130Smckusick state->dmaCurPhase = -1; 95052130Smckusick state->dmaCnt = i = regs->dmlotc; 95152130Smckusick if (dstat & SII_OBB) 95252130Smckusick state->dmaByte = regs->dmabyte; 95352130Smckusick if (i == 0) 95452130Smckusick i = SII_MAX_DMA_XFER_LENGTH; 95552130Smckusick i = state->dmalen - i; 95652130Smckusick /* note: no carry from dmaddrl to dmaddrh */ 95752130Smckusick state->dmaAddrL = regs->dmaddrl + i; 95852130Smckusick state->dmaAddrH = regs->dmaddrh; 95952130Smckusick regs->comm = comm & 96052130Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 96152130Smckusick MachEmptyWriteBuffer(); 96252130Smckusick regs->dstat = SII_DNE; 96352130Smckusick MachEmptyWriteBuffer(); 96452130Smckusick #ifdef DEBUG 96552130Smckusick if (sii_debug > 4) { 96652130Smckusick printf("SavP dcnt %d dadr %x ", 96752130Smckusick state->dmaCnt, 96852130Smckusick (state->dmaAddrH << 16) | 96952130Smckusick state->dmaAddrL); 97052130Smckusick if (((dstat & SII_OBB) != 0) ^ 97152130Smckusick (state->dmaCnt & 1)) 97252130Smckusick printf("OBB??? "); 97352130Smckusick } else if (sii_debug > 0) { 97452130Smckusick if (((dstat & SII_OBB) != 0) ^ 97552130Smckusick (state->dmaCnt & 1)) { 97652130Smckusick printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 97752130Smckusick dstat, state->dmaCnt); 97852130Smckusick sii_DumpLog(); 97952130Smckusick } 98052130Smckusick } 98152130Smckusick #endif 98252130Smckusick } 98352130Smckusick 98452130Smckusick /* read a one byte message */ 985*67205Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 0); 98652130Smckusick if (msg < 0) { 98752130Smckusick dstat = regs->dstat; 98852130Smckusick goto again; 98952130Smckusick } 99052130Smckusick #ifdef DEBUG 99152130Smckusick if (sii_debug > 4) 99252130Smckusick printf("MsgIn %x ", msg); 99352130Smckusick if (sii_logp > sii_log) 99452130Smckusick sii_logp[-1].msg = msg; 99552130Smckusick else 99652130Smckusick sii_log[NLOG - 1].msg = msg; 99752130Smckusick #endif 99852130Smckusick 99952130Smckusick /* process message */ 100052130Smckusick switch (msg) { 100152130Smckusick case SCSI_COMMAND_COMPLETE: 1002*67205Smckusick /* acknowledge last byte */ 1003*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1004*67205Smckusick (comm & SII_STATE_MSK); 1005*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1006*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1007*67205Smckusick regs->dstat = SII_DNE; 1008*67205Smckusick MachEmptyWriteBuffer(); 100952130Smckusick msg = sc->sc_target; 101052130Smckusick sc->sc_target = -1; 101152130Smckusick /* 101252130Smckusick * Wait a short time for disconnect. 101352130Smckusick * Don't be fooled if SII_BER happens first. 101452130Smckusick * Note: a reselect may happen here. 101552130Smckusick */ 101652130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 101752130Smckusick cstat & (SII_RST | SII_SCH), 101852130Smckusick SII_WAIT_COUNT, i); 101952130Smckusick if ((cstat & (SII_RST | SII_SCH | 102052130Smckusick SII_STATE_MSK)) == SII_SCH) { 102152130Smckusick regs->cstat = SII_SCH | SII_BER; 102252130Smckusick regs->comm = 0; 102352130Smckusick MachEmptyWriteBuffer(); 102452130Smckusick /* 102552130Smckusick * Double check that we didn't miss a 102652130Smckusick * state change between seeing it and 102752130Smckusick * clearing the SII_SCH bit. 102852130Smckusick */ 102952130Smckusick i = regs->cstat; 103052130Smckusick if (!(i & SII_SCH) && 103152130Smckusick (i & SII_STATE_MSK) != 103252130Smckusick (cstat & SII_STATE_MSK)) 103352130Smckusick sii_StateChg(sc, i); 103452130Smckusick } 103552130Smckusick #ifdef DEBUG 103652130Smckusick if (sii_debug > 4) 103752130Smckusick printf("cs %x\n", cstat); 103852130Smckusick #endif 103952130Smckusick sii_CmdDone(sc, msg, 0); 104052130Smckusick break; 104152130Smckusick 104252130Smckusick case SCSI_EXTENDED_MSG: 1043*67205Smckusick /* acknowledge last byte */ 1044*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1045*67205Smckusick (comm & SII_STATE_MSK); 1046*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1047*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1048*67205Smckusick regs->dstat = SII_DNE; 1049*67205Smckusick MachEmptyWriteBuffer(); 105052130Smckusick /* read the message length */ 1051*67205Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE, 1); 105252130Smckusick if (msg < 0) { 105352130Smckusick dstat = regs->dstat; 105452130Smckusick goto again; 105552130Smckusick } 1056*67205Smckusick sii_buf[1] = msg; /* message length */ 105752130Smckusick if (msg == 0) 105852130Smckusick msg = 256; 1059*67205Smckusick /* 1060*67205Smckusick * We read and acknowlege all the bytes 1061*67205Smckusick * except the last so we can assert ATN 1062*67205Smckusick * if needed before acknowledging the last. 1063*67205Smckusick */ 1064*67205Smckusick for (i = 0; i < msg; i++) { 1065*67205Smckusick dstat = sii_GetByte(regs, 1066*67205Smckusick SII_MSG_IN_PHASE, i < msg - 1); 1067*67205Smckusick if ((int)dstat < 0) { 1068*67205Smckusick dstat = regs->dstat; 1069*67205Smckusick goto again; 1070*67205Smckusick } 1071*67205Smckusick sii_buf[i + 2] = dstat; 107252130Smckusick } 107352130Smckusick 107452130Smckusick switch (sii_buf[2]) { 107552130Smckusick case SCSI_MODIFY_DATA_PTR: 1076*67205Smckusick /* acknowledge last byte */ 1077*67205Smckusick regs->comm = SII_INXFER | 1078*67205Smckusick SII_MSG_IN_PHASE | 1079*67205Smckusick (comm & SII_STATE_MSK); 1080*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1081*67205Smckusick dstat & SII_DNE, 1082*67205Smckusick SII_WAIT_COUNT, i); 1083*67205Smckusick regs->dstat = SII_DNE; 1084*67205Smckusick MachEmptyWriteBuffer(); 108552130Smckusick i = (sii_buf[3] << 24) | 108652130Smckusick (sii_buf[4] << 16) | 108752130Smckusick (sii_buf[5] << 8) | 108852130Smckusick sii_buf[6]; 108952130Smckusick if (state->dmaPrevPhase >= 0) { 109052130Smckusick state->dmaAddrL += i; 109152130Smckusick state->dmaCnt -= i; 109252130Smckusick } 109352130Smckusick break; 109452130Smckusick 109552130Smckusick case SCSI_SYNCHRONOUS_XFER: 1096*67205Smckusick /* 1097*67205Smckusick * Acknowledge last byte and 1098*67205Smckusick * signal a request for MSG_OUT. 1099*67205Smckusick */ 1100*67205Smckusick regs->comm = SII_INXFER | SII_ATN | 1101*67205Smckusick SII_MSG_IN_PHASE | 1102*67205Smckusick (comm & SII_STATE_MSK); 1103*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1104*67205Smckusick dstat & SII_DNE, 1105*67205Smckusick SII_WAIT_COUNT, i); 1106*67205Smckusick regs->dstat = SII_DNE; 1107*67205Smckusick MachEmptyWriteBuffer(); 110852130Smckusick sii_DoSync(regs, state); 110952130Smckusick break; 111052130Smckusick 111152130Smckusick default: 111252130Smckusick reject: 1113*67205Smckusick /* 1114*67205Smckusick * Acknowledge last byte and 1115*67205Smckusick * signal a request for MSG_OUT. 1116*67205Smckusick */ 1117*67205Smckusick regs->comm = SII_INXFER | SII_ATN | 1118*67205Smckusick SII_MSG_IN_PHASE | 1119*67205Smckusick (comm & SII_STATE_MSK); 1120*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1121*67205Smckusick dstat & SII_DNE, 1122*67205Smckusick SII_WAIT_COUNT, i); 1123*67205Smckusick regs->dstat = SII_DNE; 1124*67205Smckusick MachEmptyWriteBuffer(); 1125*67205Smckusick 1126*67205Smckusick /* wait for MSG_OUT phase */ 1127*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1128*67205Smckusick dstat & SII_TBE, 1129*67205Smckusick SII_WAIT_COUNT, i); 1130*67205Smckusick 113152130Smckusick /* send a reject message */ 113252130Smckusick regs->data = SCSI_MESSAGE_REJECT; 1133*67205Smckusick regs->comm = SII_INXFER | 113452130Smckusick (regs->cstat & SII_STATE_MSK) | 113552130Smckusick SII_MSG_OUT_PHASE; 113652130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1137*67205Smckusick dstat & SII_DNE, 113852130Smckusick SII_WAIT_COUNT, i); 113952130Smckusick regs->dstat = SII_DNE; 114052130Smckusick MachEmptyWriteBuffer(); 114152130Smckusick } 114252130Smckusick break; 114352130Smckusick 114452130Smckusick case SCSI_SAVE_DATA_POINTER: 114552130Smckusick case SCSI_RESTORE_POINTERS: 1146*67205Smckusick /* acknowledge last byte */ 1147*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1148*67205Smckusick (comm & SII_STATE_MSK); 1149*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1150*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1151*67205Smckusick regs->dstat = SII_DNE; 1152*67205Smckusick MachEmptyWriteBuffer(); 115352130Smckusick /* wait a short time for another msg */ 115452130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 115552130Smckusick dstat & (SII_CI | SII_DI), 115652130Smckusick SII_WAIT_COUNT, i); 115752130Smckusick if (dstat & (SII_CI | SII_DI)) { 115852130Smckusick #ifdef DEBUG 115952130Smckusick if (sii_debug > 4) 116052130Smckusick printf("cnt %d\n", i); 116152130Smckusick #endif 116252130Smckusick goto again; 116352130Smckusick } 116452130Smckusick break; 116552130Smckusick 116652130Smckusick case SCSI_DISCONNECT: 1167*67205Smckusick /* acknowledge last byte */ 1168*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1169*67205Smckusick (comm & SII_STATE_MSK); 1170*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1171*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1172*67205Smckusick regs->dstat = SII_DNE; 1173*67205Smckusick MachEmptyWriteBuffer(); 117452130Smckusick state->prevComm = comm; 117552130Smckusick #ifdef DEBUG 117652130Smckusick if (sii_debug > 4) 117752130Smckusick printf("disconn %d ", sc->sc_target); 117852130Smckusick #endif 117952130Smckusick /* 118052130Smckusick * Wait a short time for disconnect. 118152130Smckusick * Don't be fooled if SII_BER happens first. 118252130Smckusick * Note: a reselect may happen here. 118352130Smckusick */ 118452130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 118552130Smckusick cstat & (SII_RST | SII_SCH), 118652130Smckusick SII_WAIT_COUNT, i); 118752130Smckusick if ((cstat & (SII_RST | SII_SCH | 118852130Smckusick SII_STATE_MSK)) != SII_SCH) { 118952130Smckusick #ifdef DEBUG 119052130Smckusick if (sii_debug > 4) 119152130Smckusick printf("cnt %d\n", i); 119252130Smckusick #endif 119352130Smckusick dstat = regs->dstat; 119452130Smckusick goto again; 119552130Smckusick } 119652130Smckusick regs->cstat = SII_SCH | SII_BER; 119752130Smckusick regs->comm = 0; 119852130Smckusick MachEmptyWriteBuffer(); 119952130Smckusick sc->sc_target = -1; 120052130Smckusick /* 120152130Smckusick * Double check that we didn't miss a state 120252130Smckusick * change between seeing it and clearing 120352130Smckusick * the SII_SCH bit. 120452130Smckusick */ 120552130Smckusick i = regs->cstat; 120652130Smckusick if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 120752130Smckusick (cstat & SII_STATE_MSK)) 120852130Smckusick sii_StateChg(sc, i); 120952130Smckusick break; 121052130Smckusick 121152130Smckusick case SCSI_MESSAGE_REJECT: 1212*67205Smckusick /* acknowledge last byte */ 1213*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1214*67205Smckusick (comm & SII_STATE_MSK); 1215*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1216*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1217*67205Smckusick regs->dstat = SII_DNE; 1218*67205Smckusick MachEmptyWriteBuffer(); 121952130Smckusick printf("sii%d: device %d: message reject.\n", 122052130Smckusick sc - sii_softc, sc->sc_target); 1221*67205Smckusick break; 122252130Smckusick 122352130Smckusick default: 122452130Smckusick if (!(msg & SCSI_IDENTIFY)) { 1225*67205Smckusick printf("sii%d: device %d: couldn't handle message 0x%x... rejecting.\n", 122652130Smckusick sc - sii_softc, sc->sc_target, 122752130Smckusick msg); 122852130Smckusick #ifdef DEBUG 122952130Smckusick sii_DumpLog(); 123052130Smckusick #endif 1231*67205Smckusick goto reject; 123252130Smckusick } 1233*67205Smckusick /* acknowledge last byte */ 1234*67205Smckusick regs->comm = SII_INXFER | SII_MSG_IN_PHASE | 1235*67205Smckusick (comm & SII_STATE_MSK); 1236*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 1237*67205Smckusick dstat & SII_DNE, SII_WAIT_COUNT, i); 1238*67205Smckusick regs->dstat = SII_DNE; 1239*67205Smckusick MachEmptyWriteBuffer(); 124052130Smckusick /* may want to check LUN some day */ 124152130Smckusick /* wait a short time for another msg */ 124252130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 124352130Smckusick dstat & (SII_CI | SII_DI), 124452130Smckusick SII_WAIT_COUNT, i); 124552130Smckusick if (dstat & (SII_CI | SII_DI)) { 124652130Smckusick #ifdef DEBUG 124752130Smckusick if (sii_debug > 4) 124852130Smckusick printf("cnt %d\n", i); 124952130Smckusick #endif 125052130Smckusick goto again; 125152130Smckusick } 125252130Smckusick } 125352130Smckusick break; 125452130Smckusick 125552130Smckusick case SII_MSG_OUT_PHASE: 125652130Smckusick #ifdef DEBUG 125752130Smckusick if (sii_debug > 4) 125852130Smckusick printf("MsgOut\n"); 125952130Smckusick #endif 1260*67205Smckusick printf("MsgOut %x\n", state->flags); /* XXX */ 126152130Smckusick 1262*67205Smckusick /* 1263*67205Smckusick * Check for parity error. 1264*67205Smckusick * Hardware will automatically set ATN 1265*67205Smckusick * to request the device for a MSG_OUT phase. 1266*67205Smckusick */ 1267*67205Smckusick if (state->flags & PARITY_ERR) { 1268*67205Smckusick state->flags &= ~PARITY_ERR; 1269*67205Smckusick regs->data = SCSI_MESSAGE_PARITY_ERROR; 1270*67205Smckusick } else 1271*67205Smckusick regs->data = SCSI_NO_OP; 127252130Smckusick regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 127352130Smckusick SII_MSG_OUT_PHASE; 127452130Smckusick MachEmptyWriteBuffer(); 127552130Smckusick 127652130Smckusick /* wait a short time for XFER complete */ 127752130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 127852130Smckusick SII_WAIT_COUNT, i); 127952130Smckusick #ifdef DEBUG 128052130Smckusick if (sii_debug > 4) 128152130Smckusick printf("ds %x i %d\n", dstat, i); 128252130Smckusick #endif 128352130Smckusick /* just clear the DNE bit and check errors later */ 128452130Smckusick if (dstat & SII_DNE) { 128552130Smckusick regs->dstat = SII_DNE; 128652130Smckusick MachEmptyWriteBuffer(); 128752130Smckusick } 128852130Smckusick break; 128952130Smckusick 129052130Smckusick default: 129152130Smckusick printf("sii%d: Couldn't handle phase %d... ignoring.\n", 129252130Smckusick sc - sii_softc, dstat & SII_PHASE_MSK); 129352130Smckusick } 129452130Smckusick } 129552130Smckusick 129652130Smckusick #ifdef DEBUG 129752130Smckusick if (sii_debug > 3) 129852130Smckusick printf("\n"); 129952130Smckusick #endif 130052130Smckusick /* 130152130Smckusick * Check to make sure we won't be interrupted again. 130252130Smckusick * Deglitch dstat register. 130352130Smckusick */ 130452130Smckusick msg = regs->dstat; 130552130Smckusick while (msg != (dstat = regs->dstat)) 130652130Smckusick msg = dstat; 130752130Smckusick if (dstat & (SII_CI | SII_DI)) 130852130Smckusick goto again; 130952130Smckusick 131052130Smckusick if (sc->sc_target < 0) { 131152130Smckusick /* look for another device that is ready */ 131252130Smckusick for (i = 0; i < SII_NCMD; i++) { 131352130Smckusick /* don't restart a disconnected command */ 131452130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 131552130Smckusick continue; 131652130Smckusick sii_StartCmd(sc, i); 131752130Smckusick break; 131852130Smckusick } 131952130Smckusick } 132052130Smckusick return; 132152130Smckusick 132252130Smckusick abort: 132352130Smckusick /* jump here to abort the current command */ 132452130Smckusick printf("sii%d: device %d: current command terminated\n", 132552130Smckusick sc - sii_softc, sc->sc_target); 132652130Smckusick #ifdef DEBUG 132752130Smckusick sii_DumpLog(); 132852130Smckusick #endif 132952130Smckusick 133052130Smckusick if ((cstat = regs->cstat) & SII_CON) { 133152130Smckusick /* try to send an abort msg for awhile */ 133252130Smckusick regs->dstat = SII_DNE; 133352130Smckusick regs->data = SCSI_ABORT; 133452130Smckusick regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 133552130Smckusick SII_MSG_OUT_PHASE; 133652130Smckusick MachEmptyWriteBuffer(); 133752130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 133852130Smckusick (dstat & (SII_DNE | SII_PHASE_MSK)) == 133952130Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 134052130Smckusick 2 * SII_WAIT_COUNT, i); 134152130Smckusick #ifdef DEBUG 134252130Smckusick if (sii_debug > 0) 134352130Smckusick printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 134452130Smckusick #endif 134552130Smckusick if (dstat & (SII_DNE | SII_PHASE_MSK) == 134652130Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) { 134752130Smckusick /* disconnect if command in progress */ 134852130Smckusick regs->comm = SII_DISCON; 134952130Smckusick MachEmptyWriteBuffer(); 135052130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 135152130Smckusick !(cstat & SII_CON), SII_WAIT_COUNT, i); 135252130Smckusick } 135352130Smckusick } else { 135452130Smckusick #ifdef DEBUG 135552130Smckusick if (sii_debug > 0) 135652130Smckusick printf("Abort: cs %x\n", cstat); 135752130Smckusick #endif 135852130Smckusick } 135952130Smckusick regs->cstat = 0xffff; 136052130Smckusick regs->dstat = 0xffff; 136152130Smckusick regs->comm = 0; 136252130Smckusick MachEmptyWriteBuffer(); 136352130Smckusick 136452130Smckusick i = sc->sc_target; 136552130Smckusick sc->sc_target = -1; 136652130Smckusick sii_CmdDone(sc, i, EIO); 136752130Smckusick #ifdef DEBUG 136852130Smckusick if (sii_debug > 4) 136952130Smckusick printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 137052130Smckusick #endif 137152130Smckusick } 137252130Smckusick 137352130Smckusick static void 137452130Smckusick sii_StateChg(sc, cstat) 137552130Smckusick register struct siisoftc *sc; 1376*67205Smckusick register u_int cstat; 137752130Smckusick { 137852130Smckusick register SIIRegs *regs = sc->sc_regs; 137952130Smckusick register State *state; 138052130Smckusick register int i; 138152130Smckusick 138252130Smckusick #ifdef DEBUG 138352130Smckusick if (sii_debug > 4) 138452130Smckusick printf("SCH: "); 138552130Smckusick #endif 138652130Smckusick 138752130Smckusick switch (cstat & SII_STATE_MSK) { 138852130Smckusick case 0: 138952130Smckusick /* disconnect */ 139052130Smckusick i = sc->sc_target; 139152130Smckusick sc->sc_target = -1; 139252130Smckusick #ifdef DEBUG 139352130Smckusick if (sii_debug > 4) 139452130Smckusick printf("disconn %d ", i); 139552130Smckusick #endif 139652130Smckusick if (i >= 0 && !sc->sc_st[i].prevComm) { 139752130Smckusick printf("sii%d: device %d: spurrious disconnect (%d)\n", 139852130Smckusick sc - sii_softc, i, regs->slcsr); 139952130Smckusick sc->sc_st[i].prevComm = 0; 140052130Smckusick } 140152130Smckusick break; 140252130Smckusick 140352130Smckusick case SII_CON: 140452130Smckusick /* connected as initiator */ 140552130Smckusick i = regs->slcsr; 140652130Smckusick if (sc->sc_target == i) 140752130Smckusick break; 140852130Smckusick printf("sii%d: device %d: connect to device %d??\n", 140952130Smckusick sc - sii_softc, sc->sc_target, i); 141052130Smckusick sc->sc_target = i; 141152130Smckusick break; 141252130Smckusick 141352130Smckusick case SII_DST: 141452130Smckusick /* 141552130Smckusick * Wait for CON to become valid, 141652130Smckusick * chip is slow sometimes. 141752130Smckusick */ 141852130Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 141952130Smckusick cstat & SII_CON, SII_WAIT_COUNT, i); 142052130Smckusick if (!(cstat & SII_CON)) 142152130Smckusick panic("sii resel"); 142252130Smckusick /* FALLTHROUGH */ 142352130Smckusick 142452130Smckusick case SII_CON | SII_DST: 142552130Smckusick /* 142652130Smckusick * Its a reselection. Save the ID and wait for 142752130Smckusick * interrupts to tell us what to do next 142852130Smckusick * (should be MSG_IN of IDENTIFY). 142952130Smckusick * NOTE: sc_target may be >= 0 if we were in 143052130Smckusick * the process of trying to start a command 143152130Smckusick * and were reselected before the select 143252130Smckusick * command finished. 143352130Smckusick */ 143452130Smckusick sc->sc_target = i = regs->destat; 1435*67205Smckusick state = &sc->sc_st[i]; 143652130Smckusick regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 1437*67205Smckusick regs->dmctrl = state->dmaReqAck; 143852130Smckusick MachEmptyWriteBuffer(); 143952130Smckusick if (!state->prevComm) { 144052130Smckusick printf("sii%d: device %d: spurrious reselection\n", 144152130Smckusick sc - sii_softc, i); 144252130Smckusick break; 144352130Smckusick } 144452130Smckusick state->prevComm = 0; 144552130Smckusick #ifdef DEBUG 144652130Smckusick if (sii_debug > 4) 144752130Smckusick printf("resel %d ", sc->sc_target); 144852130Smckusick #endif 144952130Smckusick break; 145052130Smckusick 145152130Smckusick #ifdef notyet 145252130Smckusick case SII_DST | SII_TGT: 145352130Smckusick case SII_CON | SII_DST | SII_TGT: 145452130Smckusick /* connected as target */ 145552130Smckusick printf("sii%d: Selected by device %d as target!!\n", 145652130Smckusick sc - sii_softc, regs->destat); 145752130Smckusick regs->comm = SII_DISCON; 145852130Smckusick MachEmptyWriteBuffer(); 145952130Smckusick SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 146052130Smckusick SII_WAIT_COUNT, i); 146152130Smckusick regs->cstat = 0xffff; 146252130Smckusick regs->dstat = 0xffff; 146352130Smckusick regs->comm = 0; 146452130Smckusick break; 146552130Smckusick #endif 146652130Smckusick 146752130Smckusick default: 146852130Smckusick printf("sii%d: Unknown state change (cs %x)!!\n", 146952130Smckusick sc - sii_softc, cstat); 147052130Smckusick #ifdef DEBUG 147152130Smckusick sii_DumpLog(); 147252130Smckusick #endif 147352130Smckusick } 147452130Smckusick } 147552130Smckusick 147652130Smckusick /* 147752130Smckusick * Read one byte of data. 1478*67205Smckusick * If 'ack' is true, acknowledge the byte. 147952130Smckusick */ 148052130Smckusick static int 1481*67205Smckusick sii_GetByte(regs, phase, ack) 148252130Smckusick register SIIRegs *regs; 1483*67205Smckusick int phase, ack; 148452130Smckusick { 1485*67205Smckusick register u_int dstat; 1486*67205Smckusick register u_int state; 1487*67205Smckusick register int i; 1488*67205Smckusick register int data; 148952130Smckusick 149052130Smckusick dstat = regs->dstat; 149152130Smckusick state = regs->cstat & SII_STATE_MSK; 149252130Smckusick if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 149352130Smckusick regs->comm = state | phase; 149452130Smckusick MachEmptyWriteBuffer(); 149552130Smckusick /* wait a short time for IBF */ 149652130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 149752130Smckusick SII_WAIT_COUNT, i); 149852130Smckusick #ifdef DEBUG 149952130Smckusick if (!(dstat & SII_IBF)) 150052130Smckusick printf("status no IBF\n"); 150152130Smckusick #endif 150252130Smckusick } 1503*67205Smckusick if (dstat & SII_DNE) { /* XXX */ 150452130Smckusick printf("sii_GetByte: DNE set 5\n"); 150552130Smckusick sii_DumpLog(); 150652130Smckusick regs->dstat = SII_DNE; 150752130Smckusick } 1508*67205Smckusick data = regs->data; 1509*67205Smckusick /* check for parity error */ 1510*67205Smckusick if (dstat & SII_IPE) { 151152130Smckusick #ifdef DEBUG 151252130Smckusick if (sii_debug > 4) 151352130Smckusick printf("cnt0 %d\n", i); 151452130Smckusick #endif 1515*67205Smckusick printf("sii_GetByte: data %x ?? ds %x cm %x i %d\n", 1516*67205Smckusick data, dstat, regs->comm, i); /* XXX */ 1517*67205Smckusick data = -1; 1518*67205Smckusick ack = 1; 151952130Smckusick } 152052130Smckusick 1521*67205Smckusick if (ack) { 1522*67205Smckusick regs->comm = SII_INXFER | state | phase; 1523*67205Smckusick MachEmptyWriteBuffer(); 152452130Smckusick 1525*67205Smckusick /* wait a short time for XFER complete */ 1526*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1527*67205Smckusick SII_WAIT_COUNT, i); 152852130Smckusick 1529*67205Smckusick /* clear the DNE */ 1530*67205Smckusick if (dstat & SII_DNE) { 1531*67205Smckusick regs->dstat = SII_DNE; 1532*67205Smckusick MachEmptyWriteBuffer(); 1533*67205Smckusick } 153452130Smckusick } 153552130Smckusick 1536*67205Smckusick return (data); 153752130Smckusick } 153852130Smckusick 153952130Smckusick /* 154052130Smckusick * Exchange messages to initiate synchronous data transfers. 154152130Smckusick */ 154252130Smckusick static void 154352130Smckusick sii_DoSync(regs, state) 154452130Smckusick register SIIRegs *regs; 154552130Smckusick register State *state; 154652130Smckusick { 1547*67205Smckusick register u_int dstat, comm; 1548*67205Smckusick register int i, j; 1549*67205Smckusick u_int len; 155052130Smckusick 1551*67205Smckusick #ifdef DEBUG 1552*67205Smckusick if (sii_debug) 1553*67205Smckusick printf("sii_DoSync: len %d per %d req/ack %d\n", 1554*67205Smckusick sii_buf[1], sii_buf[3], sii_buf[4]); 1555*67205Smckusick #endif 1556*67205Smckusick 1557*67205Smckusick /* SII chip can only handle a minimum transfer period of ??? */ 1558*67205Smckusick if (sii_buf[3] < 64) 1559*67205Smckusick sii_buf[3] = 64; 1560*67205Smckusick /* SII chip can only handle a maximum REQ/ACK offset of 3 */ 156152130Smckusick len = sii_buf[4]; 156252130Smckusick if (len > 3) 1563*67205Smckusick len = 3; 156452130Smckusick 156552130Smckusick sii_buf[0] = SCSI_EXTENDED_MSG; 156652130Smckusick sii_buf[1] = 3; /* message length */ 156752130Smckusick sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 156852130Smckusick sii_buf[4] = len; 1569*67205Smckusick #if 1 1570*67205Smckusick comm = SII_INXFER | SII_ATN | SII_MSG_OUT_PHASE | 1571*67205Smckusick (regs->cstat & SII_STATE_MSK); 1572*67205Smckusick regs->comm = comm & ~SII_INXFER; 1573*67205Smckusick for (j = 0; j < 5; j++) { 1574*67205Smckusick /* wait for target to request the next byte */ 1575*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_TBE, 1576*67205Smckusick SII_WAIT_COUNT, i); 1577*67205Smckusick if (!(dstat & SII_TBE) || 1578*67205Smckusick (dstat & SII_PHASE_MSK) != SII_MSG_OUT_PHASE) { 1579*67205Smckusick printf("sii_DoSync: TBE? ds %x cm %x i %d\n", 1580*67205Smckusick dstat, comm, i); /* XXX */ 1581*67205Smckusick return; 1582*67205Smckusick } 1583*67205Smckusick 1584*67205Smckusick /* the last message byte should have ATN off */ 1585*67205Smckusick if (j == 4) 1586*67205Smckusick comm &= ~SII_ATN; 1587*67205Smckusick 1588*67205Smckusick regs->data = sii_buf[j]; 1589*67205Smckusick regs->comm = comm; 1590*67205Smckusick MachEmptyWriteBuffer(); 1591*67205Smckusick 1592*67205Smckusick /* wait a short time for XFER complete */ 1593*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 1594*67205Smckusick SII_WAIT_COUNT, i); 1595*67205Smckusick 1596*67205Smckusick if (!(dstat & SII_DNE)) { 1597*67205Smckusick printf("sii_DoSync: DNE? ds %x cm %x i %d\n", 1598*67205Smckusick dstat, comm, i); /* XXX */ 1599*67205Smckusick return; 1600*67205Smckusick } 1601*67205Smckusick 1602*67205Smckusick /* clear the DNE, other errors handled later */ 1603*67205Smckusick regs->dstat = SII_DNE; 1604*67205Smckusick MachEmptyWriteBuffer(); 1605*67205Smckusick } 1606*67205Smckusick #else 160752130Smckusick CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 1608*67205Smckusick printf("sii_DoSync: %x %x %x ds %x\n", 1609*67205Smckusick ((volatile u_short *)SII_BUF_ADDR)[0], 1610*67205Smckusick ((volatile u_short *)SII_BUF_ADDR)[2], 1611*67205Smckusick ((volatile u_short *)SII_BUF_ADDR)[4], 1612*67205Smckusick regs->dstat); /* XXX */ 1613*67205Smckusick regs->dmaddrl = (u_short)(SII_BUF_ADDR >> 1); 1614*67205Smckusick regs->dmaddrh = (u_short)(SII_BUF_ADDR >> 17) & 03; 161552130Smckusick regs->dmlotc = 5; 161652130Smckusick regs->comm = SII_DMA | SII_INXFER | SII_ATN | 161752130Smckusick (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 161852130Smckusick MachEmptyWriteBuffer(); 161952130Smckusick 162052130Smckusick /* wait a short time for XFER complete */ 162152130Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 162252130Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 162352130Smckusick SII_WAIT_COUNT, i); 162452130Smckusick 162552130Smckusick if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 162652130Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 162752130Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 162852130Smckusick sii_DumpLog(); /* XXX */ 162952130Smckusick return; 163052130Smckusick } 163152130Smckusick /* clear the DNE, other errors handled later */ 163252130Smckusick regs->dstat = SII_DNE; 163352130Smckusick MachEmptyWriteBuffer(); 1634*67205Smckusick #endif 163552130Smckusick 1636*67205Smckusick #if 0 1637*67205Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & (SII_CI | SII_DI), 1638*67205Smckusick SII_WAIT_COUNT, i); 1639*67205Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 1640*67205Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 1641*67205Smckusick #endif 1642*67205Smckusick 164352130Smckusick state->dmaReqAck = len; 164452130Smckusick } 164552130Smckusick 164652130Smckusick /* 164752130Smckusick * Issue the sequence of commands to the controller to start DMA. 164852130Smckusick * NOTE: the data buffer should be word-aligned for DMA out. 164952130Smckusick */ 165052130Smckusick static void 165152130Smckusick sii_StartDMA(regs, phase, dmaAddr, size) 165252130Smckusick register SIIRegs *regs; /* which SII to use */ 165352130Smckusick int phase; /* phase to send/receive data */ 165452130Smckusick u_short *dmaAddr; /* DMA buffer address */ 165552130Smckusick int size; /* # of bytes to transfer */ 165652130Smckusick { 165752130Smckusick 165852130Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 1659*67205Smckusick regs->dstat = SII_DNE; 166052130Smckusick printf("sii_StartDMA: DNE set\n"); 166152130Smckusick sii_DumpLog(); 166252130Smckusick } 1663*67205Smckusick regs->dmaddrl = ((u_long)dmaAddr >> 1); 1664*67205Smckusick regs->dmaddrh = ((u_long)dmaAddr >> 17) & 03; 166552130Smckusick regs->dmlotc = size; 166652130Smckusick regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 166752130Smckusick phase; 166852130Smckusick MachEmptyWriteBuffer(); 166952130Smckusick 167052130Smckusick #ifdef DEBUG 167152130Smckusick if (sii_debug > 5) { 167252130Smckusick printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 167352130Smckusick regs->cstat, regs->dstat, regs->comm, size); 167452130Smckusick } 167552130Smckusick #endif 167652130Smckusick } 167752130Smckusick 167852130Smckusick /* 167952130Smckusick * Call the device driver's 'done' routine to let it know the command is done. 168052130Smckusick * The 'done' routine may try to start another command. 168152130Smckusick * To be fair, we should start pending commands for other devices 168252130Smckusick * before allowing the same device to start another command. 168352130Smckusick */ 168452130Smckusick static void 168552130Smckusick sii_CmdDone(sc, target, error) 168652130Smckusick register struct siisoftc *sc; /* which SII to use */ 168752130Smckusick int target; /* which device is done */ 168852130Smckusick int error; /* error code if any errors */ 168952130Smckusick { 169052130Smckusick register ScsiCmd *scsicmd; 169152130Smckusick register int i; 169252130Smckusick 169352130Smckusick scsicmd = sc->sc_cmd[target]; 169452130Smckusick #ifdef DIAGNOSTIC 169552130Smckusick if (target < 0 || !scsicmd) 169652130Smckusick panic("sii_CmdDone"); 169752130Smckusick #endif 169852130Smckusick sc->sc_cmd[target] = (ScsiCmd *)0; 169952130Smckusick #ifdef DEBUG 170052130Smckusick if (sii_debug > 1) { 170152130Smckusick printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 170252130Smckusick scsicmd->sd->sd_driver->d_name, target, 170352130Smckusick scsicmd->cmd[0], error, sc->sc_st[target].buflen); 170452130Smckusick } 170552130Smckusick #endif 170652130Smckusick 170752130Smckusick /* look for another device that is ready */ 170852130Smckusick for (i = 0; i < SII_NCMD; i++) { 170952130Smckusick /* don't restart a disconnected command */ 171052130Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 171152130Smckusick continue; 171252130Smckusick sii_StartCmd(sc, i); 171352130Smckusick break; 171452130Smckusick } 171552130Smckusick 171652130Smckusick (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 171752130Smckusick sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 171852130Smckusick } 171952130Smckusick 172052130Smckusick #ifdef DEBUG 172152130Smckusick sii_DumpLog() 172252130Smckusick { 172352130Smckusick register struct sii_log *lp; 172452130Smckusick 172552130Smckusick printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 172652130Smckusick sii_debug_sz); 172763639Smckusick lp = sii_logp; 172863639Smckusick do { 1729*67205Smckusick printf("target %d cs %x ds %x cm %x msg %x rlen %x dlen %x\n", 1730*67205Smckusick lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg, 1731*67205Smckusick lp->rlen, lp->dlen); 173252130Smckusick if (++lp >= &sii_log[NLOG]) 173352130Smckusick lp = sii_log; 173463639Smckusick } while (lp != sii_logp); 173552130Smckusick } 173652130Smckusick #endif 173752130Smckusick #endif 1738