16c50d0f2Smckusick /* 26c50d0f2Smckusick * Copyright (c) 1992 Regents of the University of California. 36c50d0f2Smckusick * All rights reserved. 46c50d0f2Smckusick * 56c50d0f2Smckusick * This code is derived from software contributed to Berkeley by 66c50d0f2Smckusick * Ralph Campbell. 76c50d0f2Smckusick * 86c50d0f2Smckusick * %sccs.include.redist.c% 96c50d0f2Smckusick * 10*e9679b18Sralph * @(#)sii.c 7.4 (Berkeley) 03/29/92 116c50d0f2Smckusick * 126c50d0f2Smckusick * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c, 1302f3033eSralph * v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)"; 146c50d0f2Smckusick */ 156c50d0f2Smckusick 166c50d0f2Smckusick #include "sii.h" 176c50d0f2Smckusick #if NSII > 0 186c50d0f2Smckusick /* 196c50d0f2Smckusick * SCSI interface driver 206c50d0f2Smckusick */ 216c50d0f2Smckusick #include "param.h" 226c50d0f2Smckusick #include "systm.h" 236c50d0f2Smckusick #include "dkstat.h" 246c50d0f2Smckusick #include "buf.h" 256c50d0f2Smckusick #include "conf.h" 266c50d0f2Smckusick #include "errno.h" 276c50d0f2Smckusick 286c50d0f2Smckusick #include "machine/machConst.h" 296c50d0f2Smckusick #include "device.h" 306c50d0f2Smckusick #include "scsi.h" 316c50d0f2Smckusick #include "siireg.h" 326c50d0f2Smckusick 336c50d0f2Smckusick int siiprobe(); 346c50d0f2Smckusick void siistart(); 356c50d0f2Smckusick struct driver siidriver = { 366c50d0f2Smckusick "sii", siiprobe, siistart, 0, 376c50d0f2Smckusick }; 386c50d0f2Smckusick 396c50d0f2Smckusick typedef struct scsi_state { 406c50d0f2Smckusick int statusByte; /* status byte returned during STATUS_PHASE */ 416c50d0f2Smckusick int dmaDataPhase; /* which data phase to expect */ 426c50d0f2Smckusick int dmaCurPhase; /* SCSI phase if DMA is in progress */ 436c50d0f2Smckusick int dmaPrevPhase; /* SCSI phase of DMA suspended by disconnect */ 446c50d0f2Smckusick u_short *dmaAddr[2]; /* DMA buffer memory address */ 456c50d0f2Smckusick int dmaBufIndex; /* which of the above is currently in use */ 466c50d0f2Smckusick int dmalen; /* amount to transfer in this chunk */ 476c50d0f2Smckusick int cmdlen; /* total remaining amount of cmd to transfer */ 486c50d0f2Smckusick u_char *cmd; /* current pointer within scsicmd->cmd */ 496c50d0f2Smckusick int buflen; /* total remaining amount of data to transfer */ 506c50d0f2Smckusick char *buf; /* current pointer within scsicmd->buf */ 516c50d0f2Smckusick u_short flags; /* see below */ 526c50d0f2Smckusick u_short prevComm; /* command reg before disconnect */ 536c50d0f2Smckusick u_short dmaCtrl; /* DMA control register if disconnect */ 546c50d0f2Smckusick u_short dmaAddrL; /* DMA address register if disconnect */ 556c50d0f2Smckusick u_short dmaAddrH; /* DMA address register if disconnect */ 566c50d0f2Smckusick u_short dmaCnt; /* DMA count if disconnect */ 576c50d0f2Smckusick u_short dmaByte; /* DMA byte if disconnect on odd boundary */ 586c50d0f2Smckusick u_short dmaReqAck; /* DMA synchronous xfer offset or 0 if async */ 596c50d0f2Smckusick } State; 606c50d0f2Smckusick 616c50d0f2Smckusick /* state flags */ 626c50d0f2Smckusick #define FIRST_DMA 0x01 /* true if no data DMA started yet */ 636c50d0f2Smckusick 646c50d0f2Smckusick #define SII_NCMD 7 656c50d0f2Smckusick struct siisoftc { 666c50d0f2Smckusick SIIRegs *sc_regs; /* HW address of SII controller chip */ 676c50d0f2Smckusick int sc_flags; 686c50d0f2Smckusick int sc_target; /* target SCSI ID if connected */ 696c50d0f2Smckusick ScsiCmd *sc_cmd[SII_NCMD]; /* active command indexed by ID */ 706c50d0f2Smckusick State sc_st[SII_NCMD]; /* state info for each active command */ 716c50d0f2Smckusick } sii_softc[NSII]; 726c50d0f2Smckusick 736c50d0f2Smckusick /* 746c50d0f2Smckusick * MACROS for timing out spin loops. 756c50d0f2Smckusick * 766c50d0f2Smckusick * Wait until expression is true. 776c50d0f2Smckusick * 786c50d0f2Smckusick * Control register bits can change at any time so when the CPU 796c50d0f2Smckusick * reads a register, the bits might change and 806c50d0f2Smckusick * invalidate the setup and hold times for the CPU. 816c50d0f2Smckusick * This macro reads the register twice to be sure the value is stable. 826c50d0f2Smckusick * 836c50d0f2Smckusick * args: var - variable to save control register contents 846c50d0f2Smckusick * reg - control register to read 856c50d0f2Smckusick * expr - expression to spin on 866c50d0f2Smckusick * spincount - maximum number of times through the loop 876c50d0f2Smckusick * cntr - variable for number of tries 886c50d0f2Smckusick */ 896c50d0f2Smckusick #define SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) { \ 906c50d0f2Smckusick register unsigned tmp = reg; \ 916c50d0f2Smckusick for (cntr = 0; cntr < spincount; cntr++) { \ 926c50d0f2Smckusick while (tmp != (var = reg)) \ 936c50d0f2Smckusick tmp = var; \ 946c50d0f2Smckusick if (expr) \ 956c50d0f2Smckusick break; \ 966c50d0f2Smckusick if (cntr >= 100) \ 976c50d0f2Smckusick DELAY(100); \ 986c50d0f2Smckusick } \ 996c50d0f2Smckusick } 1006c50d0f2Smckusick 1016c50d0f2Smckusick #ifdef DEBUG 1026c50d0f2Smckusick int sii_debug = 1; 1036c50d0f2Smckusick int sii_debug_cmd; 1046c50d0f2Smckusick int sii_debug_bn; 1056c50d0f2Smckusick int sii_debug_sz; 1066c50d0f2Smckusick #define NLOG 16 1076c50d0f2Smckusick struct sii_log { 1086c50d0f2Smckusick u_short cstat; 1096c50d0f2Smckusick u_short dstat; 1106c50d0f2Smckusick u_short comm; 1116c50d0f2Smckusick u_short msg; 1126c50d0f2Smckusick int target; 1136c50d0f2Smckusick } sii_log[NLOG], *sii_logp = sii_log; 1146c50d0f2Smckusick #endif 1156c50d0f2Smckusick 1166c50d0f2Smckusick u_char sii_buf[256]; /* used for extended messages */ 1176c50d0f2Smckusick 1186c50d0f2Smckusick #define NORESET 0 1196c50d0f2Smckusick #define RESET 1 1206c50d0f2Smckusick #define NOWAIT 0 1216c50d0f2Smckusick #define WAIT 1 1226c50d0f2Smckusick 1236c50d0f2Smckusick /* define a safe address in the SCSI buffer for doing status & message DMA */ 1246c50d0f2Smckusick #define SII_BUF_ADDR (MACH_SCSI_BUFFER_ADDR + SII_MAX_DMA_XFER_LENGTH * 14) 1256c50d0f2Smckusick 1266c50d0f2Smckusick extern void sii_Reset(); 1276c50d0f2Smckusick extern void sii_StartCmd(); 1286c50d0f2Smckusick extern void sii_CmdDone(); 1296c50d0f2Smckusick extern void sii_DoIntr(); 1306c50d0f2Smckusick extern void sii_StateChg(); 1316c50d0f2Smckusick extern void sii_DoSync(); 1326c50d0f2Smckusick extern void sii_StartDMA(); 1336c50d0f2Smckusick 1346c50d0f2Smckusick /* 1356c50d0f2Smckusick * Test to see if device is present. 1366c50d0f2Smckusick * Return true if found and initialized ok. 1376c50d0f2Smckusick */ 1386c50d0f2Smckusick siiprobe(cp) 1396c50d0f2Smckusick register struct pmax_ctlr *cp; 1406c50d0f2Smckusick { 1416c50d0f2Smckusick register struct siisoftc *sc; 1426c50d0f2Smckusick register int i; 1436c50d0f2Smckusick 1446c50d0f2Smckusick if (cp->pmax_unit >= NSII) 1456c50d0f2Smckusick return (0); 1466c50d0f2Smckusick sc = &sii_softc[cp->pmax_unit]; 1476c50d0f2Smckusick sc->sc_regs = (SIIRegs *)cp->pmax_addr; 1486c50d0f2Smckusick sc->sc_flags = cp->pmax_flags; 1496c50d0f2Smckusick sc->sc_target = -1; /* no command active */ 1506c50d0f2Smckusick /* 1516c50d0f2Smckusick * Give each target its own DMA buffer region. 1526c50d0f2Smckusick * Make it big enough for 2 max transfers so we can ping pong buffers 1536c50d0f2Smckusick * while we copy the data. 1546c50d0f2Smckusick */ 1556c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) { 1566c50d0f2Smckusick sc->sc_st[i].dmaAddr[0] = (u_short *)MACH_SCSI_BUFFER_ADDR + 1576c50d0f2Smckusick 2 * SII_MAX_DMA_XFER_LENGTH * i; 1586c50d0f2Smckusick sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] + 1596c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH; 1606c50d0f2Smckusick } 1616c50d0f2Smckusick 1626c50d0f2Smckusick printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr); 1636c50d0f2Smckusick sii_Reset(sc->sc_regs, RESET); 1646c50d0f2Smckusick return (1); 1656c50d0f2Smckusick } 1666c50d0f2Smckusick 1676c50d0f2Smckusick /* 1686c50d0f2Smckusick * Start activity on a SCSI device. 1696c50d0f2Smckusick * We maintain information on each device separately since devices can 1706c50d0f2Smckusick * connect/disconnect during an operation. 1716c50d0f2Smckusick */ 1726c50d0f2Smckusick void 1736c50d0f2Smckusick siistart(scsicmd) 1746c50d0f2Smckusick register ScsiCmd *scsicmd; /* command to start */ 1756c50d0f2Smckusick { 1766c50d0f2Smckusick register struct scsi_device *sdp = scsicmd->sd; 1776c50d0f2Smckusick register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr]; 1786c50d0f2Smckusick int s; 1796c50d0f2Smckusick 1806c50d0f2Smckusick s = splbio(); 1816c50d0f2Smckusick /* 1826c50d0f2Smckusick * Check if another command is already in progress. 1836c50d0f2Smckusick * We may have to change this if we allow SCSI devices with 1846c50d0f2Smckusick * separate LUNs. 1856c50d0f2Smckusick */ 1866c50d0f2Smckusick if (sc->sc_cmd[sdp->sd_drive]) { 1876c50d0f2Smckusick printf("sii%d: device %s busy at start\n", sdp->sd_ctlr, 1886c50d0f2Smckusick sdp->sd_driver->d_name); 1896c50d0f2Smckusick (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 1906c50d0f2Smckusick scsicmd->buflen, 0); 1916c50d0f2Smckusick splx(s); 1926c50d0f2Smckusick } 1936c50d0f2Smckusick sc->sc_cmd[sdp->sd_drive] = scsicmd; 1946c50d0f2Smckusick sii_StartCmd(sc, sdp->sd_drive); 1956c50d0f2Smckusick splx(s); 1966c50d0f2Smckusick } 1976c50d0f2Smckusick 1986c50d0f2Smckusick /* 1996c50d0f2Smckusick * Check to see if any SII chips have pending interrupts 2006c50d0f2Smckusick * and process as appropriate. 2016c50d0f2Smckusick */ 2026c50d0f2Smckusick void 20383f001d9Sralph siiintr(unit) 20483f001d9Sralph int unit; 2056c50d0f2Smckusick { 20683f001d9Sralph register struct siisoftc *sc = &sii_softc[unit]; 2076c50d0f2Smckusick unsigned dstat; 2086c50d0f2Smckusick 2096c50d0f2Smckusick /* 2106c50d0f2Smckusick * Find which controller caused the interrupt. 2116c50d0f2Smckusick */ 2126c50d0f2Smckusick dstat = sc->sc_regs->dstat; 21383f001d9Sralph if (dstat & (SII_CI | SII_DI)) 2146c50d0f2Smckusick sii_DoIntr(sc, dstat); 2156c50d0f2Smckusick } 2166c50d0f2Smckusick 2176c50d0f2Smckusick /* 2186c50d0f2Smckusick * Reset the SII chip and do a SCSI reset if 'reset' is true. 2196c50d0f2Smckusick * NOTE: if !cold && reset, should probably probe for devices 2206c50d0f2Smckusick * since a SCSI bus reset will set UNIT_ATTENTION. 2216c50d0f2Smckusick */ 2226c50d0f2Smckusick static void 2236c50d0f2Smckusick sii_Reset(regs, reset) 2246c50d0f2Smckusick register SIIRegs *regs; 2256c50d0f2Smckusick int reset; /* TRUE => reset SCSI bus */ 2266c50d0f2Smckusick { 2276c50d0f2Smckusick 2286c50d0f2Smckusick #ifdef DEBUG 2296c50d0f2Smckusick if (sii_debug > 1) 2306c50d0f2Smckusick printf("sii: RESET\n"); 2316c50d0f2Smckusick #endif 2326c50d0f2Smckusick /* 2336c50d0f2Smckusick * Reset the SII chip. 2346c50d0f2Smckusick */ 2356c50d0f2Smckusick regs->comm = SII_CHRESET; 2366c50d0f2Smckusick /* 2376c50d0f2Smckusick * Set arbitrated bus mode. 2386c50d0f2Smckusick */ 2396c50d0f2Smckusick regs->csr = SII_HPM; 2406c50d0f2Smckusick /* 2416c50d0f2Smckusick * SII is always ID 7. 2426c50d0f2Smckusick */ 2436c50d0f2Smckusick regs->id = SII_ID_IO | 7; 2446c50d0f2Smckusick /* 2456c50d0f2Smckusick * Enable SII to drive the SCSI bus. 2466c50d0f2Smckusick */ 2476c50d0f2Smckusick regs->dictrl = SII_PRE; 2486c50d0f2Smckusick regs->dmctrl = 0; 2496c50d0f2Smckusick 2506c50d0f2Smckusick if (reset) { 2516c50d0f2Smckusick register int i; 2526c50d0f2Smckusick 2536c50d0f2Smckusick /* 2546c50d0f2Smckusick * Assert SCSI bus reset for at least 25 Usec to clear the 2556c50d0f2Smckusick * world. SII_DO_RST is self clearing. 2566c50d0f2Smckusick * Delay 250 ms before doing any commands. 2576c50d0f2Smckusick */ 2586c50d0f2Smckusick regs->comm = SII_DO_RST; 2596c50d0f2Smckusick MachEmptyWriteBuffer(); 2606c50d0f2Smckusick DELAY(250000); 2616c50d0f2Smckusick 2626c50d0f2Smckusick /* rearbitrate synchronous offset */ 2636c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) 2646c50d0f2Smckusick sii_softc[0].sc_st[i].dmaReqAck = 0; 2656c50d0f2Smckusick } 2666c50d0f2Smckusick 2676c50d0f2Smckusick /* 2686c50d0f2Smckusick * Clear any pending interrupts from the reset. 2696c50d0f2Smckusick */ 2706c50d0f2Smckusick regs->cstat = regs->cstat; 2716c50d0f2Smckusick regs->dstat = regs->dstat; 2726c50d0f2Smckusick /* 2736c50d0f2Smckusick * Set up SII for arbitrated bus mode, SCSI parity checking, 2746c50d0f2Smckusick * Reselect Enable, and Interrupt Enable. 2756c50d0f2Smckusick */ 2766c50d0f2Smckusick regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE; 2776c50d0f2Smckusick MachEmptyWriteBuffer(); 2786c50d0f2Smckusick } 2796c50d0f2Smckusick 2806c50d0f2Smckusick /* 2816c50d0f2Smckusick * Start a SCSI command by sending the cmd data 2826c50d0f2Smckusick * to a SCSI controller via the SII. 2836c50d0f2Smckusick * Call the device done proceedure if it can't be started. 2846c50d0f2Smckusick * NOTE: we should be called with interrupts disabled. 2856c50d0f2Smckusick */ 2866c50d0f2Smckusick static void 2876c50d0f2Smckusick sii_StartCmd(sc, target) 2886c50d0f2Smckusick register struct siisoftc *sc; /* which SII to use */ 2896c50d0f2Smckusick register int target; /* which command to start */ 2906c50d0f2Smckusick { 2916c50d0f2Smckusick register SIIRegs *regs; 2926c50d0f2Smckusick register ScsiCmd *scsicmd; 2936c50d0f2Smckusick register State *state; 2946c50d0f2Smckusick register unsigned status; 2956c50d0f2Smckusick int error, retval; 2966c50d0f2Smckusick 2976c50d0f2Smckusick /* if another command is currently in progress, just wait */ 2986c50d0f2Smckusick if (sc->sc_target >= 0) 2996c50d0f2Smckusick return; 3006c50d0f2Smckusick 3016c50d0f2Smckusick /* initialize state information for this command */ 3026c50d0f2Smckusick scsicmd = sc->sc_cmd[target]; 3036c50d0f2Smckusick state = &sc->sc_st[target]; 3046c50d0f2Smckusick state->flags = FIRST_DMA; 3056c50d0f2Smckusick state->prevComm = 0; 3066c50d0f2Smckusick state->dmalen = 0; 3076c50d0f2Smckusick state->dmaCurPhase = -1; 3086c50d0f2Smckusick state->dmaPrevPhase = -1; 3096c50d0f2Smckusick state->dmaBufIndex = 0; 3106c50d0f2Smckusick state->cmd = scsicmd->cmd; 3116c50d0f2Smckusick state->cmdlen = scsicmd->cmdlen; 3126c50d0f2Smckusick if ((state->buflen = scsicmd->buflen) == 0) { 3136c50d0f2Smckusick state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */ 3146c50d0f2Smckusick state->buf = (char *)0; 3156c50d0f2Smckusick } else { 3166c50d0f2Smckusick state->dmaDataPhase = 3176c50d0f2Smckusick (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ? 3186c50d0f2Smckusick SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE; 3196c50d0f2Smckusick state->buf = scsicmd->buf; 3206c50d0f2Smckusick } 3216c50d0f2Smckusick 3226c50d0f2Smckusick #ifdef DEBUG 3236c50d0f2Smckusick if (sii_debug > 1) { 3246c50d0f2Smckusick printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n", 3256c50d0f2Smckusick scsicmd->sd->sd_driver->d_name, target, 3266c50d0f2Smckusick scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen, 3276c50d0f2Smckusick state->dmaDataPhase); 3286c50d0f2Smckusick } 3296c50d0f2Smckusick sii_debug_cmd = scsicmd->cmd[0]; 3306c50d0f2Smckusick if (scsicmd->cmd[0] == SCSI_READ_EXT) { 3316c50d0f2Smckusick sii_debug_bn = (scsicmd->cmd[2] << 24) | 3326c50d0f2Smckusick (scsicmd->cmd[3] << 16) | 3336c50d0f2Smckusick (scsicmd->cmd[4] << 8) | 3346c50d0f2Smckusick scsicmd->cmd[5]; 3356c50d0f2Smckusick sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 3366c50d0f2Smckusick } 3376c50d0f2Smckusick #endif 3386c50d0f2Smckusick 3396c50d0f2Smckusick /* try to select the target */ 3406c50d0f2Smckusick regs = sc->sc_regs; 3416c50d0f2Smckusick 3426c50d0f2Smckusick /* 3436c50d0f2Smckusick * Another device may have selected us; in which case, 3446c50d0f2Smckusick * this command will be restarted later. 3456c50d0f2Smckusick */ 3466c50d0f2Smckusick if ((status = regs->dstat) & (SII_CI | SII_DI)) { 3476c50d0f2Smckusick sii_DoIntr(sc, status); 3486c50d0f2Smckusick return; 3496c50d0f2Smckusick } 3506c50d0f2Smckusick 3516c50d0f2Smckusick sc->sc_target = target; 3526c50d0f2Smckusick if (scsicmd->flags & SCSICMD_USE_SYNC) { 3536c50d0f2Smckusick printf("sii_StartCmd: doing extended msg\n"); /* XXX */ 3546c50d0f2Smckusick /* 3556c50d0f2Smckusick * Setup to send both the identify message and the synchronous 3566c50d0f2Smckusick * data transfer request. 3576c50d0f2Smckusick */ 3586c50d0f2Smckusick sii_buf[0] = SCSI_DIS_REC_IDENTIFY; 3596c50d0f2Smckusick sii_buf[1] = SCSI_EXTENDED_MSG; 3606c50d0f2Smckusick sii_buf[2] = 3; /* message length */ 3616c50d0f2Smckusick sii_buf[3] = SCSI_SYNCHRONOUS_XFER; 3626c50d0f2Smckusick sii_buf[4] = 0; 3636c50d0f2Smckusick sii_buf[5] = 3; /* maximum SII chip supports */ 3646c50d0f2Smckusick 3656c50d0f2Smckusick state->dmaCurPhase = SII_MSG_OUT_PHASE, 3666c50d0f2Smckusick state->dmalen = 6; 3676c50d0f2Smckusick CopyToBuffer((u_short *)sii_buf, 3686c50d0f2Smckusick (volatile u_short *)SII_BUF_ADDR, 6); 3696c50d0f2Smckusick regs->slcsr = target; 3706c50d0f2Smckusick regs->dmctrl = 0; 3716c50d0f2Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 3726c50d0f2Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 3736c50d0f2Smckusick regs->dmlotc = 6; 3746c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN | 3756c50d0f2Smckusick SII_CON | SII_MSG_OUT_PHASE; 3766c50d0f2Smckusick } else { 3776c50d0f2Smckusick /* do a chained, select with ATN and programmed I/O command */ 3786c50d0f2Smckusick regs->data = SCSI_DIS_REC_IDENTIFY; 3796c50d0f2Smckusick regs->slcsr = target; 3806c50d0f2Smckusick regs->dmctrl = 0; 3816c50d0f2Smckusick regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON | 3826c50d0f2Smckusick SII_MSG_OUT_PHASE; 3836c50d0f2Smckusick } 3846c50d0f2Smckusick MachEmptyWriteBuffer(); 3856c50d0f2Smckusick 3866c50d0f2Smckusick /* 3876c50d0f2Smckusick * Wait for something to happen 3886c50d0f2Smckusick * (should happen soon or we would use interrupts). 3896c50d0f2Smckusick */ 3906c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI), 391*e9679b18Sralph SII_WAIT_COUNT/4, retval); 3926c50d0f2Smckusick 3936c50d0f2Smckusick /* check to see if we are connected OK */ 3946c50d0f2Smckusick if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) == 3956c50d0f2Smckusick (SII_SCH | SII_CON)) { 3966c50d0f2Smckusick regs->cstat = status; 3976c50d0f2Smckusick MachEmptyWriteBuffer(); 3986c50d0f2Smckusick 3996c50d0f2Smckusick #ifdef DEBUG 4006c50d0f2Smckusick sii_logp->target = target; 4016c50d0f2Smckusick sii_logp->cstat = status; 4026c50d0f2Smckusick sii_logp->dstat = 0; 4036c50d0f2Smckusick sii_logp->comm = regs->comm; 4046c50d0f2Smckusick sii_logp->msg = -1; 4056c50d0f2Smckusick if (++sii_logp >= &sii_log[NLOG]) 4066c50d0f2Smckusick sii_logp = sii_log; 4076c50d0f2Smckusick #endif 4086c50d0f2Smckusick 4096c50d0f2Smckusick /* wait a short time for command phase */ 4106c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS, 4116c50d0f2Smckusick SII_WAIT_COUNT, retval); 4126c50d0f2Smckusick #ifdef DEBUG 4136c50d0f2Smckusick if (sii_debug > 2) 4146c50d0f2Smckusick printf("sii_StartCmd: ds %x cnt %d\n", status, retval); 4156c50d0f2Smckusick #endif 4166c50d0f2Smckusick if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) != 4176c50d0f2Smckusick (SII_MIS | SII_CMD_PHASE)) { 4186c50d0f2Smckusick printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n", 4196c50d0f2Smckusick regs->cstat, status, retval); /* XXX */ 4206c50d0f2Smckusick /* process interrupt or continue until it happens */ 4216c50d0f2Smckusick if (status & (SII_CI | SII_DI)) 4226c50d0f2Smckusick sii_DoIntr(sc, status); 4236c50d0f2Smckusick return; 4246c50d0f2Smckusick } 4256c50d0f2Smckusick regs->dstat = SII_DNE; /* clear Msg Out DMA done */ 4266c50d0f2Smckusick 4276c50d0f2Smckusick /* send command data */ 4286c50d0f2Smckusick CopyToBuffer((u_short *)state->cmd, 4296c50d0f2Smckusick (volatile u_short *)state->dmaAddr[0], state->cmdlen); 4306c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE, 4316c50d0f2Smckusick state->dmaAddr[0], state->dmalen = scsicmd->cmdlen); 4326c50d0f2Smckusick 4336c50d0f2Smckusick /* wait a little while for DMA to finish */ 4346c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI), 4356c50d0f2Smckusick SII_WAIT_COUNT, retval); 4366c50d0f2Smckusick #ifdef DEBUG 4376c50d0f2Smckusick if (sii_debug > 2) 4386c50d0f2Smckusick printf("sii_StartCmd: ds %x, cnt %d\n", status, retval); 4396c50d0f2Smckusick #endif 4406c50d0f2Smckusick if (status & (SII_CI | SII_DI)) 4416c50d0f2Smckusick sii_DoIntr(sc, status); 4426c50d0f2Smckusick #ifdef DEBUG 4436c50d0f2Smckusick if (sii_debug > 2) 4446c50d0f2Smckusick printf("sii_StartCmd: DONE ds %x\n", regs->dstat); 4456c50d0f2Smckusick #endif 4466c50d0f2Smckusick return; 4476c50d0f2Smckusick } 4486c50d0f2Smckusick 4496c50d0f2Smckusick /* 4506c50d0f2Smckusick * Another device may have selected us; in which case, 4516c50d0f2Smckusick * this command will be restarted later. 4526c50d0f2Smckusick */ 4536c50d0f2Smckusick if (status & (SII_CI | SII_DI)) { 4546c50d0f2Smckusick sii_DoIntr(sc, regs->dstat); 4556c50d0f2Smckusick return; 4566c50d0f2Smckusick } 4576c50d0f2Smckusick 4586c50d0f2Smckusick /* 4596c50d0f2Smckusick * Disconnect if selection command still in progress. 4606c50d0f2Smckusick */ 4616c50d0f2Smckusick if (status & SII_SIP) { 4626c50d0f2Smckusick error = ENXIO; /* device didn't respond */ 4636c50d0f2Smckusick regs->comm = SII_DISCON; 4646c50d0f2Smckusick MachEmptyWriteBuffer(); 4656c50d0f2Smckusick SII_WAIT_UNTIL(status, regs->cstat, 4666c50d0f2Smckusick !(status & (SII_CON | SII_SIP)), 4676c50d0f2Smckusick SII_WAIT_COUNT, retval); 4686c50d0f2Smckusick } else 4696c50d0f2Smckusick error = EBUSY; /* couldn't get the bus */ 4706c50d0f2Smckusick #ifdef DEBUG 471*e9679b18Sralph if (sii_debug > 1) 4726c50d0f2Smckusick printf("sii_StartCmd: Couldn't select target %d error %d\n", 4736c50d0f2Smckusick target, error); 4746c50d0f2Smckusick #endif 4756c50d0f2Smckusick sc->sc_target = -1; 4766c50d0f2Smckusick regs->cstat = 0xffff; 4776c50d0f2Smckusick regs->dstat = 0xffff; 4786c50d0f2Smckusick regs->comm = 0; 4796c50d0f2Smckusick MachEmptyWriteBuffer(); 4806c50d0f2Smckusick sii_CmdDone(sc, target, error); 4816c50d0f2Smckusick } 4826c50d0f2Smckusick 4836c50d0f2Smckusick /* 4846c50d0f2Smckusick * Process interrupt conditions. 4856c50d0f2Smckusick */ 4866c50d0f2Smckusick static void 4876c50d0f2Smckusick sii_DoIntr(sc, dstat) 4886c50d0f2Smckusick register struct siisoftc *sc; 4896c50d0f2Smckusick register unsigned dstat; 4906c50d0f2Smckusick { 4916c50d0f2Smckusick register SIIRegs *regs = sc->sc_regs; 4926c50d0f2Smckusick register State *state; 4936c50d0f2Smckusick register unsigned cstat; 4946c50d0f2Smckusick register int i; 4956c50d0f2Smckusick unsigned comm, msg; 4966c50d0f2Smckusick 4976c50d0f2Smckusick again: 4986c50d0f2Smckusick comm = regs->comm; 4996c50d0f2Smckusick 5006c50d0f2Smckusick #ifdef DEBUG 5016c50d0f2Smckusick if (sii_debug > 3) 5026c50d0f2Smckusick printf("sii_DoIntr: cs %x, ds %x cm %x ", 5036c50d0f2Smckusick regs->cstat, dstat, comm); 5046c50d0f2Smckusick sii_logp->target = sc->sc_target; 5056c50d0f2Smckusick sii_logp->cstat = regs->cstat; 5066c50d0f2Smckusick sii_logp->dstat = dstat; 5076c50d0f2Smckusick sii_logp->comm = comm; 5086c50d0f2Smckusick sii_logp->msg = -1; 5096c50d0f2Smckusick if (++sii_logp >= &sii_log[NLOG]) 5106c50d0f2Smckusick sii_logp = sii_log; 5116c50d0f2Smckusick #endif 5126c50d0f2Smckusick 5136c50d0f2Smckusick regs->dstat = dstat; /* acknowledge everything */ 5146c50d0f2Smckusick MachEmptyWriteBuffer(); 5156c50d0f2Smckusick 5166c50d0f2Smckusick if (dstat & SII_CI) { 5176c50d0f2Smckusick /* deglitch cstat register */ 5186c50d0f2Smckusick msg = regs->cstat; 5196c50d0f2Smckusick while (msg != (cstat = regs->cstat)) 5206c50d0f2Smckusick msg = cstat; 5216c50d0f2Smckusick regs->cstat = cstat; /* acknowledge everything */ 5226c50d0f2Smckusick MachEmptyWriteBuffer(); 5236c50d0f2Smckusick #ifdef DEBUG 5246c50d0f2Smckusick if (sii_logp > sii_log) 5256c50d0f2Smckusick sii_logp[-1].cstat = cstat; 5266c50d0f2Smckusick else 5276c50d0f2Smckusick sii_log[NLOG - 1].cstat = cstat; 5286c50d0f2Smckusick #endif 5296c50d0f2Smckusick 5306c50d0f2Smckusick /* check for a BUS RESET */ 5316c50d0f2Smckusick if (cstat & SII_RST) { 5326c50d0f2Smckusick printf("sii%d: SCSI bus reset!!\n", sc - sii_softc); 5336c50d0f2Smckusick /* need to flush disconnected commands */ 53483f001d9Sralph for (i = 0; i < SII_NCMD; i++) { 53583f001d9Sralph if (!sc->sc_cmd[i]) 53683f001d9Sralph continue; 5376c50d0f2Smckusick sii_CmdDone(sc, i, EIO); 53883f001d9Sralph } 5396c50d0f2Smckusick /* rearbitrate synchronous offset */ 5406c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) 5416c50d0f2Smckusick sc->sc_st[i].dmaReqAck = 0; 5426c50d0f2Smckusick sc->sc_target = -1; 5436c50d0f2Smckusick return; 5446c50d0f2Smckusick } 5456c50d0f2Smckusick 5466c50d0f2Smckusick #ifdef notdef 5476c50d0f2Smckusick /* 5486c50d0f2Smckusick * Check for a BUS ERROR. 5496c50d0f2Smckusick * According to DEC, this feature doesn't really work 5506c50d0f2Smckusick * and to just clear the bit if it's set. 5516c50d0f2Smckusick */ 5526c50d0f2Smckusick if (cstat & SII_BER) { 5536c50d0f2Smckusick } 5546c50d0f2Smckusick #endif 5556c50d0f2Smckusick 5566c50d0f2Smckusick /* check for state change */ 5576c50d0f2Smckusick if (cstat & SII_SCH) { 5586c50d0f2Smckusick sii_StateChg(sc, cstat); 5596c50d0f2Smckusick comm = regs->comm; 5606c50d0f2Smckusick } 5616c50d0f2Smckusick } 5626c50d0f2Smckusick 5636c50d0f2Smckusick /* check for DMA completion */ 5646c50d0f2Smckusick if (dstat & SII_DNE) { 5656c50d0f2Smckusick u_short *dma; 5666c50d0f2Smckusick char *buf; 5676c50d0f2Smckusick 5686c50d0f2Smckusick /* check for a PARITY ERROR */ 5696c50d0f2Smckusick if (dstat & SII_IPE) { 5706c50d0f2Smckusick printf("sii%d: Parity error!!\n", sc - sii_softc); 5716c50d0f2Smckusick goto abort; 5726c50d0f2Smckusick } 5736c50d0f2Smckusick /* 5746c50d0f2Smckusick * There is a race condition with SII_SCH. There is a short 5756c50d0f2Smckusick * window between the time a SII_SCH is seen after a disconnect 5766c50d0f2Smckusick * and when the SII_SCH is cleared. A reselect can happen 5776c50d0f2Smckusick * in this window and we will clear the SII_SCH without 5786c50d0f2Smckusick * processing the reconnect. 5796c50d0f2Smckusick */ 5806c50d0f2Smckusick if (sc->sc_target < 0) { 5816c50d0f2Smckusick cstat = regs->cstat; 5826c50d0f2Smckusick printf("sii%d: target %d DNE?? dev %d,%d cs %x\n", 5836c50d0f2Smckusick sc - sii_softc, sc->sc_target, 5846c50d0f2Smckusick regs->slcsr, regs->destat, 5856c50d0f2Smckusick cstat); /* XXX */ 5866c50d0f2Smckusick if (cstat & SII_DST) { 5876c50d0f2Smckusick sc->sc_target = regs->destat; 5886c50d0f2Smckusick state->prevComm = 0; 5896c50d0f2Smckusick } else 5906c50d0f2Smckusick panic("sc_target 1"); 5916c50d0f2Smckusick } 5926c50d0f2Smckusick state = &sc->sc_st[sc->sc_target]; 5936c50d0f2Smckusick /* dmalen = amount left to transfer, i = amount transfered */ 5946c50d0f2Smckusick i = state->dmalen; 5956c50d0f2Smckusick state->dmalen = 0; 5966c50d0f2Smckusick state->dmaCurPhase = -1; 5976c50d0f2Smckusick #ifdef DEBUG 5986c50d0f2Smckusick if (sii_debug > 4) { 5996c50d0f2Smckusick printf("DNE: amt %d ", i); 6006c50d0f2Smckusick if (!(dstat & SII_TCZ)) 6016c50d0f2Smckusick printf("no TCZ?? (%d) ", regs->dmlotc); 6026c50d0f2Smckusick } else if (!(dstat & SII_TCZ)) { 6036c50d0f2Smckusick printf("sii%d: device %d: no TCZ?? (%d)\n", 6046c50d0f2Smckusick sc - sii_softc, sc->sc_target, regs->dmlotc); 6056c50d0f2Smckusick sii_DumpLog(); /* XXX */ 6066c50d0f2Smckusick } 6076c50d0f2Smckusick #endif 6086c50d0f2Smckusick switch (comm & SII_PHASE_MSK) { 6096c50d0f2Smckusick case SII_CMD_PHASE: 6106c50d0f2Smckusick state->cmdlen -= i; 6116c50d0f2Smckusick break; 6126c50d0f2Smckusick 6136c50d0f2Smckusick case SII_DATA_IN_PHASE: 6146c50d0f2Smckusick /* check for more data for the same phase */ 6156c50d0f2Smckusick dma = state->dmaAddr[state->dmaBufIndex]; 6166c50d0f2Smckusick buf = state->buf; 6176c50d0f2Smckusick state->buf += i; 6186c50d0f2Smckusick state->buflen -= i; 6196c50d0f2Smckusick if (state->buflen > 0 && !(dstat & SII_MIS)) { 6206c50d0f2Smckusick int len; 6216c50d0f2Smckusick 6226c50d0f2Smckusick /* start reading next chunk */ 6236c50d0f2Smckusick len = state->buflen; 6246c50d0f2Smckusick if (len > SII_MAX_DMA_XFER_LENGTH) 6256c50d0f2Smckusick len = SII_MAX_DMA_XFER_LENGTH; 6266c50d0f2Smckusick state->dmaBufIndex = !state->dmaBufIndex; 6276c50d0f2Smckusick sii_StartDMA(regs, 6286c50d0f2Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 6296c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 6306c50d0f2Smckusick state->dmalen = len); 6316c50d0f2Smckusick dstat &= ~(SII_IBF | SII_TBE); 6326c50d0f2Smckusick } 6336c50d0f2Smckusick /* copy in the data */ 6346c50d0f2Smckusick CopyFromBuffer((volatile u_short *)dma, buf, i); 6356c50d0f2Smckusick break; 6366c50d0f2Smckusick 6376c50d0f2Smckusick case SII_DATA_OUT_PHASE: 6386c50d0f2Smckusick state->dmaBufIndex = !state->dmaBufIndex; 6396c50d0f2Smckusick state->buf += i; 6406c50d0f2Smckusick state->buflen -= i; 6416c50d0f2Smckusick 6426c50d0f2Smckusick /* check for more data for the same phase */ 6436c50d0f2Smckusick if (state->buflen <= 0 || (dstat & SII_MIS)) 6446c50d0f2Smckusick break; 6456c50d0f2Smckusick 6466c50d0f2Smckusick /* start next chunk */ 6476c50d0f2Smckusick i = state->buflen; 6486c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) { 6496c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase = 6506c50d0f2Smckusick SII_DATA_OUT_PHASE, 6516c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 6526c50d0f2Smckusick state->dmalen = 6536c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH); 6546c50d0f2Smckusick /* prepare for next chunk */ 6556c50d0f2Smckusick i -= SII_MAX_DMA_XFER_LENGTH; 6566c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 6576c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH; 6586c50d0f2Smckusick CopyToBuffer((u_short *)(state->buf + 6596c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH), 6606c50d0f2Smckusick (volatile u_short *) 6616c50d0f2Smckusick state->dmaAddr[!state->dmaBufIndex], i); 6626c50d0f2Smckusick } else { 6636c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase = 6646c50d0f2Smckusick SII_DATA_OUT_PHASE, 6656c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 6666c50d0f2Smckusick state->dmalen = i); 6676c50d0f2Smckusick } 6686c50d0f2Smckusick dstat &= ~(SII_IBF | SII_TBE); 6696c50d0f2Smckusick break; 6706c50d0f2Smckusick 6716c50d0f2Smckusick default: 6726c50d0f2Smckusick printf("sii%d: device %d: unexpected DNE\n", 6736c50d0f2Smckusick sc - sii_softc, sc->sc_target); 6746c50d0f2Smckusick #ifdef DEBUG 6756c50d0f2Smckusick sii_DumpLog(); 6766c50d0f2Smckusick #endif 6776c50d0f2Smckusick } 6786c50d0f2Smckusick } 6796c50d0f2Smckusick 6806c50d0f2Smckusick /* check for phase change or another MsgIn/Out */ 6816c50d0f2Smckusick if (dstat & (SII_MIS | SII_IBF | SII_TBE)) { 6826c50d0f2Smckusick /* 6836c50d0f2Smckusick * There is a race condition with SII_SCH. There is a short 6846c50d0f2Smckusick * window between the time a SII_SCH is seen after a disconnect 6856c50d0f2Smckusick * and when the SII_SCH is cleared. A reselect can happen 6866c50d0f2Smckusick * in this window and we will clear the SII_SCH without 6876c50d0f2Smckusick * processing the reconnect. 6886c50d0f2Smckusick */ 6896c50d0f2Smckusick if (sc->sc_target < 0) { 6906c50d0f2Smckusick cstat = regs->cstat; 6916c50d0f2Smckusick printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n", 6926c50d0f2Smckusick sc - sii_softc, sc->sc_target, 6936c50d0f2Smckusick regs->slcsr, regs->destat, 6946c50d0f2Smckusick cstat, dstat); /* XXX */ 6956c50d0f2Smckusick if (cstat & SII_DST) { 6966c50d0f2Smckusick sc->sc_target = regs->destat; 6976c50d0f2Smckusick state->prevComm = 0; 6986c50d0f2Smckusick } else 6996c50d0f2Smckusick panic("sc_target 2"); 7006c50d0f2Smckusick } 7016c50d0f2Smckusick state = &sc->sc_st[sc->sc_target]; 7026c50d0f2Smckusick switch (dstat & SII_PHASE_MSK) { 7036c50d0f2Smckusick case SII_CMD_PHASE: 7046c50d0f2Smckusick if (state->dmaPrevPhase >= 0) { 7056c50d0f2Smckusick /* restart DMA after disconnect/reconnect */ 7066c50d0f2Smckusick if (state->dmaPrevPhase != SII_CMD_PHASE) { 7076c50d0f2Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 7086c50d0f2Smckusick sc - sii_softc, sc->sc_target); 7096c50d0f2Smckusick goto abort; 7106c50d0f2Smckusick } 7116c50d0f2Smckusick state->dmaCurPhase = SII_CMD_PHASE; 7126c50d0f2Smckusick state->dmaPrevPhase = -1; 7136c50d0f2Smckusick regs->dmaddrl = state->dmaAddrL; 7146c50d0f2Smckusick regs->dmaddrh = state->dmaAddrH; 7156c50d0f2Smckusick regs->dmlotc = state->dmaCnt; 7166c50d0f2Smckusick if (state->dmaCnt & 1) 7176c50d0f2Smckusick regs->dmabyte = state->dmaByte; 7186c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | 7196c50d0f2Smckusick (comm & SII_STATE_MSK) | SII_CMD_PHASE; 7206c50d0f2Smckusick MachEmptyWriteBuffer(); 7216c50d0f2Smckusick #ifdef DEBUG 7226c50d0f2Smckusick if (sii_debug > 4) 7236c50d0f2Smckusick printf("Cmd dcnt %d dadr %x ", 7246c50d0f2Smckusick state->dmaCnt, 7256c50d0f2Smckusick (state->dmaAddrH << 16) | 7266c50d0f2Smckusick state->dmaAddrL); 7276c50d0f2Smckusick #endif 7286c50d0f2Smckusick } else { 7296c50d0f2Smckusick /* send command data */ 7306c50d0f2Smckusick i = state->cmdlen; 7316c50d0f2Smckusick if (i == 0) { 7326c50d0f2Smckusick printf("sii%d: device %d: cmd count exceeded\n", 7336c50d0f2Smckusick sc - sii_softc, sc->sc_target); 7346c50d0f2Smckusick goto abort; 7356c50d0f2Smckusick } 7366c50d0f2Smckusick CopyToBuffer((u_short *)state->cmd, 7376c50d0f2Smckusick (volatile u_short *)state->dmaAddr[0], 7386c50d0f2Smckusick i); 7396c50d0f2Smckusick sii_StartDMA(regs, state->dmaCurPhase = 7406c50d0f2Smckusick SII_CMD_PHASE, state->dmaAddr[0], 7416c50d0f2Smckusick state->dmalen = i); 7426c50d0f2Smckusick } 7436c50d0f2Smckusick /* wait a short time for XFER complete */ 7446c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 7456c50d0f2Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 7466c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) { 7476c50d0f2Smckusick #ifdef DEBUG 7486c50d0f2Smckusick if (sii_debug > 4) 7496c50d0f2Smckusick printf("cnt %d\n", i); 7506c50d0f2Smckusick else if (sii_debug > 0) 7516c50d0f2Smckusick printf("sii_DoIntr: cmd wait ds %x cnt %d\n", 7526c50d0f2Smckusick dstat, i); 7536c50d0f2Smckusick #endif 7546c50d0f2Smckusick goto again; 7556c50d0f2Smckusick } 7566c50d0f2Smckusick break; 7576c50d0f2Smckusick 7586c50d0f2Smckusick case SII_DATA_IN_PHASE: 7596c50d0f2Smckusick case SII_DATA_OUT_PHASE: 7606c50d0f2Smckusick regs->dmctrl = state->dmaReqAck; 7616c50d0f2Smckusick if (state->cmdlen > 0) { 7626c50d0f2Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n", 7636c50d0f2Smckusick sc - sii_softc, sc->sc_target, 7646c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 7656c50d0f2Smckusick state->cmdlen); 7666c50d0f2Smckusick state->cmdlen = 0; 7676c50d0f2Smckusick #ifdef DEBUG 7686c50d0f2Smckusick sii_DumpLog(); 7696c50d0f2Smckusick #endif 7706c50d0f2Smckusick } 7716c50d0f2Smckusick if (state->dmaPrevPhase >= 0) { 7726c50d0f2Smckusick /* restart DMA after disconnect/reconnect */ 7736c50d0f2Smckusick if (state->dmaPrevPhase != 7746c50d0f2Smckusick (dstat & SII_PHASE_MSK)) { 7756c50d0f2Smckusick printf("sii%d: device %d: dma reselect phase doesn't match\n", 7766c50d0f2Smckusick sc - sii_softc, sc->sc_target); 7776c50d0f2Smckusick goto abort; 7786c50d0f2Smckusick } 7796c50d0f2Smckusick state->dmaCurPhase = state->dmaPrevPhase; 7806c50d0f2Smckusick state->dmaPrevPhase = -1; 7816c50d0f2Smckusick regs->dmaddrl = state->dmaAddrL; 7826c50d0f2Smckusick regs->dmaddrh = state->dmaAddrH; 7836c50d0f2Smckusick regs->dmlotc = state->dmaCnt; 7846c50d0f2Smckusick if (state->dmaCnt & 1) 7856c50d0f2Smckusick regs->dmabyte = state->dmaByte; 7866c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | 7876c50d0f2Smckusick (comm & SII_STATE_MSK) | 7886c50d0f2Smckusick state->dmaCurPhase; 7896c50d0f2Smckusick MachEmptyWriteBuffer(); 7906c50d0f2Smckusick #ifdef DEBUG 7916c50d0f2Smckusick if (sii_debug > 4) 7926c50d0f2Smckusick printf("Data %d dcnt %d dadr %x ", 7936c50d0f2Smckusick state->dmaDataPhase, 7946c50d0f2Smckusick state->dmaCnt, 7956c50d0f2Smckusick (state->dmaAddrH << 16) | 7966c50d0f2Smckusick state->dmaAddrL); 7976c50d0f2Smckusick #endif 7986c50d0f2Smckusick break; 7996c50d0f2Smckusick } 8006c50d0f2Smckusick if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) { 8016c50d0f2Smckusick printf("sii%d: device %d: cmd %x: dma phase doesn't match\n", 8026c50d0f2Smckusick sc - sii_softc, sc->sc_target, 8036c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0]); 8046c50d0f2Smckusick goto abort; 8056c50d0f2Smckusick } 8066c50d0f2Smckusick #ifdef DEBUG 8076c50d0f2Smckusick if (sii_debug > 4) { 8086c50d0f2Smckusick printf("Data %d ", state->dmaDataPhase); 8096c50d0f2Smckusick if (sii_debug > 5) 8106c50d0f2Smckusick printf("\n"); 8116c50d0f2Smckusick } 8126c50d0f2Smckusick #endif 8136c50d0f2Smckusick i = state->buflen; 8146c50d0f2Smckusick if (i == 0) { 8156c50d0f2Smckusick printf("sii%d: device %d: data count exceeded\n", 8166c50d0f2Smckusick sc - sii_softc, sc->sc_target); 8176c50d0f2Smckusick goto abort; 8186c50d0f2Smckusick } 8196c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 8206c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH; 8216c50d0f2Smckusick if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) { 8226c50d0f2Smckusick sii_StartDMA(regs, 8236c50d0f2Smckusick state->dmaCurPhase = SII_DATA_IN_PHASE, 8246c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 8256c50d0f2Smckusick state->dmalen = i); 8266c50d0f2Smckusick break; 8276c50d0f2Smckusick } 8286c50d0f2Smckusick /* start first chunk */ 8296c50d0f2Smckusick if (state->flags & FIRST_DMA) { 8306c50d0f2Smckusick state->flags &= ~FIRST_DMA; 8316c50d0f2Smckusick CopyToBuffer((u_short *)state->buf, 8326c50d0f2Smckusick (volatile u_short *) 8336c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], i); 8346c50d0f2Smckusick } 8356c50d0f2Smckusick sii_StartDMA(regs, 8366c50d0f2Smckusick state->dmaCurPhase = SII_DATA_OUT_PHASE, 8376c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 8386c50d0f2Smckusick state->dmalen = i); 8396c50d0f2Smckusick i = state->buflen - SII_MAX_DMA_XFER_LENGTH; 8406c50d0f2Smckusick if (i > 0) { 8416c50d0f2Smckusick /* prepare for next chunk */ 8426c50d0f2Smckusick if (i > SII_MAX_DMA_XFER_LENGTH) 8436c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH; 8446c50d0f2Smckusick CopyToBuffer((u_short *)(state->buf + 8456c50d0f2Smckusick SII_MAX_DMA_XFER_LENGTH), 8466c50d0f2Smckusick (volatile u_short *) 8476c50d0f2Smckusick state->dmaAddr[!state->dmaBufIndex], i); 8486c50d0f2Smckusick } 8496c50d0f2Smckusick break; 8506c50d0f2Smckusick 8516c50d0f2Smckusick case SII_STATUS_PHASE: 8526c50d0f2Smckusick if (state->cmdlen > 0) { 8536c50d0f2Smckusick printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n", 8546c50d0f2Smckusick sc - sii_softc, sc->sc_target, 8556c50d0f2Smckusick sc->sc_cmd[sc->sc_target]->cmd[0], 8566c50d0f2Smckusick state->cmdlen); 8576c50d0f2Smckusick state->cmdlen = 0; 8586c50d0f2Smckusick #ifdef DEBUG 8596c50d0f2Smckusick sii_DumpLog(); 8606c50d0f2Smckusick #endif 8616c50d0f2Smckusick } 8626c50d0f2Smckusick 8636c50d0f2Smckusick /* read amount transfered if DMA didn't finish */ 8646c50d0f2Smckusick if (state->dmalen > 0) { 8656c50d0f2Smckusick i = state->dmalen - regs->dmlotc; 8666c50d0f2Smckusick state->dmalen = 0; 8676c50d0f2Smckusick state->dmaCurPhase = -1; 8686c50d0f2Smckusick regs->dmlotc = 0; 8696c50d0f2Smckusick regs->comm = comm & 8706c50d0f2Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 8716c50d0f2Smckusick MachEmptyWriteBuffer(); 8726c50d0f2Smckusick regs->dstat = SII_DNE; 8736c50d0f2Smckusick MachEmptyWriteBuffer(); 8746c50d0f2Smckusick #ifdef DEBUG 8756c50d0f2Smckusick if (sii_debug > 4) 8766c50d0f2Smckusick printf("DMA amt %d ", i); 8776c50d0f2Smckusick #endif 8786c50d0f2Smckusick switch (comm & SII_PHASE_MSK) { 8796c50d0f2Smckusick case SII_DATA_IN_PHASE: 8806c50d0f2Smckusick /* copy in the data */ 8816c50d0f2Smckusick CopyFromBuffer((volatile u_short *) 8826c50d0f2Smckusick state->dmaAddr[state->dmaBufIndex], 8836c50d0f2Smckusick state->buf, i); 8846c50d0f2Smckusick 8856c50d0f2Smckusick case SII_CMD_PHASE: 8866c50d0f2Smckusick case SII_DATA_OUT_PHASE: 8876c50d0f2Smckusick state->buflen -= i; 8886c50d0f2Smckusick } 8896c50d0f2Smckusick } 8906c50d0f2Smckusick 8916c50d0f2Smckusick /* read a one byte status message */ 8926c50d0f2Smckusick state->statusByte = msg = 8936c50d0f2Smckusick sii_GetByte(regs, SII_STATUS_PHASE); 8946c50d0f2Smckusick if (msg < 0) { 8956c50d0f2Smckusick dstat = regs->dstat; 8966c50d0f2Smckusick goto again; 8976c50d0f2Smckusick } 8986c50d0f2Smckusick #ifdef DEBUG 8996c50d0f2Smckusick if (sii_debug > 4) 9006c50d0f2Smckusick printf("Status %x ", msg); 9016c50d0f2Smckusick if (sii_logp > sii_log) 9026c50d0f2Smckusick sii_logp[-1].msg = msg; 9036c50d0f2Smckusick else 9046c50d0f2Smckusick sii_log[NLOG - 1].msg = msg; 9056c50d0f2Smckusick #endif 9066c50d0f2Smckusick 9076c50d0f2Smckusick /* do a quick wait for COMMAND_COMPLETE */ 9086c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 9096c50d0f2Smckusick dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i); 9106c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) { 9116c50d0f2Smckusick #ifdef DEBUG 9126c50d0f2Smckusick if (sii_debug > 4) 9136c50d0f2Smckusick printf("cnt2 %d\n", i); 9146c50d0f2Smckusick #endif 9156c50d0f2Smckusick goto again; 9166c50d0f2Smckusick } 9176c50d0f2Smckusick break; 9186c50d0f2Smckusick 9196c50d0f2Smckusick case SII_MSG_IN_PHASE: 9206c50d0f2Smckusick /* 9216c50d0f2Smckusick * Save DMA state if DMA didn't finish. 9226c50d0f2Smckusick * Be careful not to save state again after reconnect 9236c50d0f2Smckusick * and see RESTORE_POINTER message. 9246c50d0f2Smckusick * Note that the SII DMA address is not incremented 9256c50d0f2Smckusick * as DMA proceeds. 9266c50d0f2Smckusick */ 9276c50d0f2Smckusick if (state->dmaCurPhase > 0) { 9286c50d0f2Smckusick /* save dma registers */ 9296c50d0f2Smckusick state->dmaPrevPhase = state->dmaCurPhase; 9306c50d0f2Smckusick state->dmaCurPhase = -1; 9316c50d0f2Smckusick state->dmaCnt = i = regs->dmlotc; 9326c50d0f2Smckusick if (dstat & SII_OBB) 9336c50d0f2Smckusick state->dmaByte = regs->dmabyte; 9346c50d0f2Smckusick if (i == 0) 9356c50d0f2Smckusick i = SII_MAX_DMA_XFER_LENGTH; 9366c50d0f2Smckusick i = state->dmalen - i; 9376c50d0f2Smckusick /* note: no carry from dmaddrl to dmaddrh */ 9386c50d0f2Smckusick state->dmaAddrL = regs->dmaddrl + i; 9396c50d0f2Smckusick state->dmaAddrH = regs->dmaddrh; 9406c50d0f2Smckusick regs->comm = comm & 9416c50d0f2Smckusick (SII_STATE_MSK | SII_PHASE_MSK); 9426c50d0f2Smckusick MachEmptyWriteBuffer(); 9436c50d0f2Smckusick regs->dstat = SII_DNE; 9446c50d0f2Smckusick MachEmptyWriteBuffer(); 9456c50d0f2Smckusick #ifdef DEBUG 9466c50d0f2Smckusick if (sii_debug > 4) { 9476c50d0f2Smckusick printf("SavP dcnt %d dadr %x ", 9486c50d0f2Smckusick state->dmaCnt, 9496c50d0f2Smckusick (state->dmaAddrH << 16) | 9506c50d0f2Smckusick state->dmaAddrL); 9516c50d0f2Smckusick if (((dstat & SII_OBB) != 0) ^ 9526c50d0f2Smckusick (state->dmaCnt & 1)) 9536c50d0f2Smckusick printf("OBB??? "); 9546c50d0f2Smckusick } else if (sii_debug > 0) { 9556c50d0f2Smckusick if (((dstat & SII_OBB) != 0) ^ 9566c50d0f2Smckusick (state->dmaCnt & 1)) { 9576c50d0f2Smckusick printf("sii_DoIntr: OBB??? ds %x cnt %d\n", 9586c50d0f2Smckusick dstat, state->dmaCnt); 9596c50d0f2Smckusick sii_DumpLog(); 9606c50d0f2Smckusick } 9616c50d0f2Smckusick } 9626c50d0f2Smckusick #endif 9636c50d0f2Smckusick } 9646c50d0f2Smckusick 9656c50d0f2Smckusick /* read a one byte message */ 9666c50d0f2Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 9676c50d0f2Smckusick if (msg < 0) { 9686c50d0f2Smckusick dstat = regs->dstat; 9696c50d0f2Smckusick goto again; 9706c50d0f2Smckusick } 9716c50d0f2Smckusick #ifdef DEBUG 9726c50d0f2Smckusick if (sii_debug > 4) 9736c50d0f2Smckusick printf("MsgIn %x ", msg); 9746c50d0f2Smckusick if (sii_logp > sii_log) 9756c50d0f2Smckusick sii_logp[-1].msg = msg; 9766c50d0f2Smckusick else 9776c50d0f2Smckusick sii_log[NLOG - 1].msg = msg; 9786c50d0f2Smckusick #endif 9796c50d0f2Smckusick 9806c50d0f2Smckusick /* process message */ 9816c50d0f2Smckusick switch (msg) { 9826c50d0f2Smckusick case SCSI_COMMAND_COMPLETE: 9836c50d0f2Smckusick msg = sc->sc_target; 9846c50d0f2Smckusick sc->sc_target = -1; 9856c50d0f2Smckusick /* 9866c50d0f2Smckusick * Wait a short time for disconnect. 9876c50d0f2Smckusick * Don't be fooled if SII_BER happens first. 9886c50d0f2Smckusick * Note: a reselect may happen here. 9896c50d0f2Smckusick */ 9906c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 9916c50d0f2Smckusick cstat & (SII_RST | SII_SCH), 9926c50d0f2Smckusick SII_WAIT_COUNT, i); 9936c50d0f2Smckusick if ((cstat & (SII_RST | SII_SCH | 9946c50d0f2Smckusick SII_STATE_MSK)) == SII_SCH) { 9956c50d0f2Smckusick regs->cstat = SII_SCH | SII_BER; 9966c50d0f2Smckusick regs->comm = 0; 9976c50d0f2Smckusick MachEmptyWriteBuffer(); 9986c50d0f2Smckusick /* 9996c50d0f2Smckusick * Double check that we didn't miss a 10006c50d0f2Smckusick * state change between seeing it and 10016c50d0f2Smckusick * clearing the SII_SCH bit. 10026c50d0f2Smckusick */ 10036c50d0f2Smckusick i = regs->cstat; 10046c50d0f2Smckusick if (!(i & SII_SCH) && 10056c50d0f2Smckusick (i & SII_STATE_MSK) != 10066c50d0f2Smckusick (cstat & SII_STATE_MSK)) 10076c50d0f2Smckusick sii_StateChg(sc, i); 10086c50d0f2Smckusick } 10096c50d0f2Smckusick #ifdef DEBUG 10106c50d0f2Smckusick if (sii_debug > 4) 10116c50d0f2Smckusick printf("cs %x\n", cstat); 10126c50d0f2Smckusick #endif 10136c50d0f2Smckusick sii_CmdDone(sc, msg, 0); 10146c50d0f2Smckusick break; 10156c50d0f2Smckusick 10166c50d0f2Smckusick case SCSI_EXTENDED_MSG: 10176c50d0f2Smckusick /* read the message length */ 10186c50d0f2Smckusick msg = sii_GetByte(regs, SII_MSG_IN_PHASE); 10196c50d0f2Smckusick if (msg < 0) { 10206c50d0f2Smckusick dstat = regs->dstat; 10216c50d0f2Smckusick goto again; 10226c50d0f2Smckusick } 10236c50d0f2Smckusick if (msg == 0) 10246c50d0f2Smckusick msg = 256; 10256c50d0f2Smckusick sii_StartDMA(regs, SII_MSG_IN_PHASE, 10266c50d0f2Smckusick (u_short *)SII_BUF_ADDR, msg); 10276c50d0f2Smckusick /* wait a short time for XFER complete */ 10286c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 10296c50d0f2Smckusick (dstat & (SII_DNE | SII_TCZ)) == 10306c50d0f2Smckusick (SII_DNE | SII_TCZ), 10316c50d0f2Smckusick SII_WAIT_COUNT, i); 10326c50d0f2Smckusick 10336c50d0f2Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != 10346c50d0f2Smckusick (SII_DNE | SII_TCZ)) { 10356c50d0f2Smckusick #ifdef DEBUG 10366c50d0f2Smckusick if (sii_debug > 4) 10376c50d0f2Smckusick printf("cnt0 %d\n", i); 10386c50d0f2Smckusick else if (sii_debug > 0) 10396c50d0f2Smckusick printf("sii_DoIntr: emsg in ds %x cnt %d\n", 10406c50d0f2Smckusick dstat, i); 10416c50d0f2Smckusick #endif 10426c50d0f2Smckusick printf("sii: ds %x cm %x i %d lotc %d\n", 10436c50d0f2Smckusick dstat, comm, i, regs->dmlotc); /* XXX */ 10446c50d0f2Smckusick sii_DumpLog(); /* XXX */ 10456c50d0f2Smckusick goto again; 10466c50d0f2Smckusick } 10476c50d0f2Smckusick 10486c50d0f2Smckusick /* clear the DNE, other errors handled later */ 10496c50d0f2Smckusick regs->dstat = SII_DNE; 10506c50d0f2Smckusick MachEmptyWriteBuffer(); 10516c50d0f2Smckusick 10526c50d0f2Smckusick CopyFromBuffer((volatile u_short *)SII_BUF_ADDR, 10536c50d0f2Smckusick sii_buf + 2, msg); 10546c50d0f2Smckusick switch (sii_buf[2]) { 10556c50d0f2Smckusick case SCSI_MODIFY_DATA_PTR: 10566c50d0f2Smckusick i = (sii_buf[3] << 24) | 10576c50d0f2Smckusick (sii_buf[4] << 16) | 10586c50d0f2Smckusick (sii_buf[5] << 8) | 10596c50d0f2Smckusick sii_buf[6]; 10606c50d0f2Smckusick if (state->dmaPrevPhase >= 0) { 10616c50d0f2Smckusick state->dmaAddrL += i; 10626c50d0f2Smckusick state->dmaCnt -= i; 10636c50d0f2Smckusick } 10646c50d0f2Smckusick break; 10656c50d0f2Smckusick 10666c50d0f2Smckusick case SCSI_SYNCHRONOUS_XFER: 10676c50d0f2Smckusick sii_DoSync(regs, state); 10686c50d0f2Smckusick break; 10696c50d0f2Smckusick 10706c50d0f2Smckusick case SCSI_EXTENDED_IDENTIFY: 10716c50d0f2Smckusick case SCSI_WIDE_XFER: 10726c50d0f2Smckusick default: 10736c50d0f2Smckusick reject: 10746c50d0f2Smckusick /* send a reject message */ 10756c50d0f2Smckusick regs->data = SCSI_MESSAGE_REJECT; 10766c50d0f2Smckusick regs->comm = SII_INXFER | SII_ATN | 10776c50d0f2Smckusick (regs->cstat & SII_STATE_MSK) | 10786c50d0f2Smckusick SII_MSG_OUT_PHASE; 10796c50d0f2Smckusick MachEmptyWriteBuffer(); 10806c50d0f2Smckusick /* wait for XFER complete */ 10816c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 10826c50d0f2Smckusick (dstat & 10836c50d0f2Smckusick (SII_DNE | SII_PHASE_MSK)) == 10846c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 10856c50d0f2Smckusick SII_WAIT_COUNT, i); 10866c50d0f2Smckusick 10876c50d0f2Smckusick if ((dstat & 10886c50d0f2Smckusick (SII_DNE | SII_PHASE_MSK)) != 10896c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) 10906c50d0f2Smckusick break; 10916c50d0f2Smckusick regs->dstat = SII_DNE; 10926c50d0f2Smckusick MachEmptyWriteBuffer(); 10936c50d0f2Smckusick } 10946c50d0f2Smckusick break; 10956c50d0f2Smckusick 10966c50d0f2Smckusick case SCSI_SAVE_DATA_POINTER: 10976c50d0f2Smckusick case SCSI_RESTORE_POINTERS: 10986c50d0f2Smckusick /* wait a short time for another msg */ 10996c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 11006c50d0f2Smckusick dstat & (SII_CI | SII_DI), 11016c50d0f2Smckusick SII_WAIT_COUNT, i); 11026c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) { 11036c50d0f2Smckusick #ifdef DEBUG 11046c50d0f2Smckusick if (sii_debug > 4) 11056c50d0f2Smckusick printf("cnt %d\n", i); 11066c50d0f2Smckusick #endif 11076c50d0f2Smckusick goto again; 11086c50d0f2Smckusick } 11096c50d0f2Smckusick break; 11106c50d0f2Smckusick 11116c50d0f2Smckusick case SCSI_DISCONNECT: 11126c50d0f2Smckusick state->prevComm = comm; 11136c50d0f2Smckusick #ifdef DEBUG 11146c50d0f2Smckusick if (sii_debug > 4) 11156c50d0f2Smckusick printf("disconn %d ", sc->sc_target); 11166c50d0f2Smckusick #endif 11176c50d0f2Smckusick /* 11186c50d0f2Smckusick * Wait a short time for disconnect. 11196c50d0f2Smckusick * Don't be fooled if SII_BER happens first. 11206c50d0f2Smckusick * Note: a reselect may happen here. 11216c50d0f2Smckusick */ 11226c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 11236c50d0f2Smckusick cstat & (SII_RST | SII_SCH), 11246c50d0f2Smckusick SII_WAIT_COUNT, i); 11256c50d0f2Smckusick if ((cstat & (SII_RST | SII_SCH | 11266c50d0f2Smckusick SII_STATE_MSK)) != SII_SCH) { 11276c50d0f2Smckusick #ifdef DEBUG 11286c50d0f2Smckusick if (sii_debug > 4) 11296c50d0f2Smckusick printf("cnt %d\n", i); 11306c50d0f2Smckusick #endif 11316c50d0f2Smckusick dstat = regs->dstat; 11326c50d0f2Smckusick goto again; 11336c50d0f2Smckusick } 11346c50d0f2Smckusick regs->cstat = SII_SCH | SII_BER; 11356c50d0f2Smckusick regs->comm = 0; 11366c50d0f2Smckusick MachEmptyWriteBuffer(); 11376c50d0f2Smckusick sc->sc_target = -1; 11386c50d0f2Smckusick /* 11396c50d0f2Smckusick * Double check that we didn't miss a state 11406c50d0f2Smckusick * change between seeing it and clearing 11416c50d0f2Smckusick * the SII_SCH bit. 11426c50d0f2Smckusick */ 11436c50d0f2Smckusick i = regs->cstat; 11446c50d0f2Smckusick if (!(i & SII_SCH) && (i & SII_STATE_MSK) != 11456c50d0f2Smckusick (cstat & SII_STATE_MSK)) 11466c50d0f2Smckusick sii_StateChg(sc, i); 11476c50d0f2Smckusick break; 11486c50d0f2Smckusick 11496c50d0f2Smckusick case SCSI_MESSAGE_REJECT: 11506c50d0f2Smckusick printf("sii%d: device %d: message reject.\n", 11516c50d0f2Smckusick sc - sii_softc, sc->sc_target); 11526c50d0f2Smckusick goto abort; 11536c50d0f2Smckusick 11546c50d0f2Smckusick default: 11556c50d0f2Smckusick if (!(msg & SCSI_IDENTIFY)) { 11566c50d0f2Smckusick printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n", 11576c50d0f2Smckusick sc - sii_softc, sc->sc_target, 11586c50d0f2Smckusick msg); 11596c50d0f2Smckusick #ifdef DEBUG 11606c50d0f2Smckusick sii_DumpLog(); 11616c50d0f2Smckusick #endif 11626c50d0f2Smckusick break; 11636c50d0f2Smckusick } 11646c50d0f2Smckusick /* may want to check LUN some day */ 11656c50d0f2Smckusick /* wait a short time for another msg */ 11666c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 11676c50d0f2Smckusick dstat & (SII_CI | SII_DI), 11686c50d0f2Smckusick SII_WAIT_COUNT, i); 11696c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) { 11706c50d0f2Smckusick #ifdef DEBUG 11716c50d0f2Smckusick if (sii_debug > 4) 11726c50d0f2Smckusick printf("cnt %d\n", i); 11736c50d0f2Smckusick #endif 11746c50d0f2Smckusick goto again; 11756c50d0f2Smckusick } 11766c50d0f2Smckusick } 11776c50d0f2Smckusick break; 11786c50d0f2Smckusick 11796c50d0f2Smckusick case SII_MSG_OUT_PHASE: 11806c50d0f2Smckusick #ifdef DEBUG 11816c50d0f2Smckusick if (sii_debug > 4) 11826c50d0f2Smckusick printf("MsgOut\n"); 11836c50d0f2Smckusick #endif 11846c50d0f2Smckusick 11856c50d0f2Smckusick regs->data = SCSI_NO_OP; 11866c50d0f2Smckusick regs->comm = SII_INXFER | (comm & SII_STATE_MSK) | 11876c50d0f2Smckusick SII_MSG_OUT_PHASE; 11886c50d0f2Smckusick MachEmptyWriteBuffer(); 11896c50d0f2Smckusick 11906c50d0f2Smckusick /* wait a short time for XFER complete */ 11916c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 11926c50d0f2Smckusick SII_WAIT_COUNT, i); 11936c50d0f2Smckusick #ifdef DEBUG 11946c50d0f2Smckusick if (sii_debug > 4) 11956c50d0f2Smckusick printf("ds %x i %d\n", dstat, i); 11966c50d0f2Smckusick #endif 11976c50d0f2Smckusick /* just clear the DNE bit and check errors later */ 11986c50d0f2Smckusick if (dstat & SII_DNE) { 11996c50d0f2Smckusick regs->dstat = SII_DNE; 12006c50d0f2Smckusick MachEmptyWriteBuffer(); 12016c50d0f2Smckusick } 12026c50d0f2Smckusick break; 12036c50d0f2Smckusick 12046c50d0f2Smckusick default: 12056c50d0f2Smckusick printf("sii%d: Couldn't handle phase %d... ignoring.\n", 12066c50d0f2Smckusick sc - sii_softc, dstat & SII_PHASE_MSK); 12076c50d0f2Smckusick } 12086c50d0f2Smckusick } 12096c50d0f2Smckusick 12106c50d0f2Smckusick #ifdef DEBUG 12116c50d0f2Smckusick if (sii_debug > 3) 12126c50d0f2Smckusick printf("\n"); 12136c50d0f2Smckusick #endif 12146c50d0f2Smckusick /* 12156c50d0f2Smckusick * Check to make sure we won't be interrupted again. 12166c50d0f2Smckusick * Deglitch dstat register. 12176c50d0f2Smckusick */ 12186c50d0f2Smckusick msg = regs->dstat; 12196c50d0f2Smckusick while (msg != (dstat = regs->dstat)) 12206c50d0f2Smckusick msg = dstat; 12216c50d0f2Smckusick if (dstat & (SII_CI | SII_DI)) 12226c50d0f2Smckusick goto again; 12236c50d0f2Smckusick 12246c50d0f2Smckusick if (sc->sc_target < 0) { 12256c50d0f2Smckusick /* look for another device that is ready */ 12266c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) { 12276c50d0f2Smckusick /* don't restart a disconnected command */ 12286c50d0f2Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 12296c50d0f2Smckusick continue; 12306c50d0f2Smckusick sii_StartCmd(sc, i); 12316c50d0f2Smckusick break; 12326c50d0f2Smckusick } 12336c50d0f2Smckusick } 12346c50d0f2Smckusick return; 12356c50d0f2Smckusick 12366c50d0f2Smckusick abort: 12376c50d0f2Smckusick /* jump here to abort the current command */ 12386c50d0f2Smckusick printf("sii%d: device %d: current command terminated\n", 12396c50d0f2Smckusick sc - sii_softc, sc->sc_target); 12406c50d0f2Smckusick #ifdef DEBUG 12416c50d0f2Smckusick sii_DumpLog(); 12426c50d0f2Smckusick #endif 12436c50d0f2Smckusick 12446c50d0f2Smckusick if ((cstat = regs->cstat) & SII_CON) { 12456c50d0f2Smckusick /* try to send an abort msg for awhile */ 12466c50d0f2Smckusick regs->dstat = SII_DNE; 12476c50d0f2Smckusick regs->data = SCSI_ABORT; 12486c50d0f2Smckusick regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) | 12496c50d0f2Smckusick SII_MSG_OUT_PHASE; 12506c50d0f2Smckusick MachEmptyWriteBuffer(); 12516c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 12526c50d0f2Smckusick (dstat & (SII_DNE | SII_PHASE_MSK)) == 12536c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE), 12546c50d0f2Smckusick 2 * SII_WAIT_COUNT, i); 12556c50d0f2Smckusick #ifdef DEBUG 12566c50d0f2Smckusick if (sii_debug > 0) 12576c50d0f2Smckusick printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i); 12586c50d0f2Smckusick #endif 12596c50d0f2Smckusick if (dstat & (SII_DNE | SII_PHASE_MSK) == 12606c50d0f2Smckusick (SII_DNE | SII_MSG_OUT_PHASE)) { 12616c50d0f2Smckusick /* disconnect if command in progress */ 12626c50d0f2Smckusick regs->comm = SII_DISCON; 12636c50d0f2Smckusick MachEmptyWriteBuffer(); 12646c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 12656c50d0f2Smckusick !(cstat & SII_CON), SII_WAIT_COUNT, i); 12666c50d0f2Smckusick } 12676c50d0f2Smckusick } else { 12686c50d0f2Smckusick #ifdef DEBUG 12696c50d0f2Smckusick if (sii_debug > 0) 12706c50d0f2Smckusick printf("Abort: cs %x\n", cstat); 12716c50d0f2Smckusick #endif 12726c50d0f2Smckusick } 12736c50d0f2Smckusick regs->cstat = 0xffff; 12746c50d0f2Smckusick regs->dstat = 0xffff; 12756c50d0f2Smckusick regs->comm = 0; 12766c50d0f2Smckusick MachEmptyWriteBuffer(); 12776c50d0f2Smckusick 12786c50d0f2Smckusick i = sc->sc_target; 12796c50d0f2Smckusick sc->sc_target = -1; 12806c50d0f2Smckusick sii_CmdDone(sc, i, EIO); 12816c50d0f2Smckusick #ifdef DEBUG 12826c50d0f2Smckusick if (sii_debug > 4) 12836c50d0f2Smckusick printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target); 12846c50d0f2Smckusick #endif 12856c50d0f2Smckusick } 12866c50d0f2Smckusick 12876c50d0f2Smckusick static void 12886c50d0f2Smckusick sii_StateChg(sc, cstat) 12896c50d0f2Smckusick register struct siisoftc *sc; 12906c50d0f2Smckusick register unsigned cstat; 12916c50d0f2Smckusick { 12926c50d0f2Smckusick register SIIRegs *regs = sc->sc_regs; 12936c50d0f2Smckusick register State *state; 12946c50d0f2Smckusick register int i; 12956c50d0f2Smckusick 12966c50d0f2Smckusick #ifdef DEBUG 12976c50d0f2Smckusick if (sii_debug > 4) 12986c50d0f2Smckusick printf("SCH: "); 12996c50d0f2Smckusick #endif 13006c50d0f2Smckusick 13016c50d0f2Smckusick switch (cstat & SII_STATE_MSK) { 13026c50d0f2Smckusick case 0: 13036c50d0f2Smckusick /* disconnect */ 13046c50d0f2Smckusick i = sc->sc_target; 13056c50d0f2Smckusick sc->sc_target = -1; 13066c50d0f2Smckusick #ifdef DEBUG 13076c50d0f2Smckusick if (sii_debug > 4) 13086c50d0f2Smckusick printf("disconn %d ", i); 13096c50d0f2Smckusick #endif 13106c50d0f2Smckusick if (i >= 0 && !sc->sc_st[i].prevComm) { 13116c50d0f2Smckusick printf("sii%d: device %d: spurrious disconnect (%d)\n", 13126c50d0f2Smckusick sc - sii_softc, i, regs->slcsr); 13136c50d0f2Smckusick sc->sc_st[i].prevComm = 0; 13146c50d0f2Smckusick } 13156c50d0f2Smckusick break; 13166c50d0f2Smckusick 13176c50d0f2Smckusick case SII_CON: 13186c50d0f2Smckusick /* connected as initiator */ 13196c50d0f2Smckusick i = regs->slcsr; 13206c50d0f2Smckusick if (sc->sc_target == i) 13216c50d0f2Smckusick break; 13226c50d0f2Smckusick printf("sii%d: device %d: connect to device %d??\n", 13236c50d0f2Smckusick sc - sii_softc, sc->sc_target, i); 13246c50d0f2Smckusick sc->sc_target = i; 13256c50d0f2Smckusick break; 13266c50d0f2Smckusick 13276c50d0f2Smckusick case SII_DST: 13286c50d0f2Smckusick /* 13296c50d0f2Smckusick * Wait for CON to become valid, 13306c50d0f2Smckusick * chip is slow sometimes. 13316c50d0f2Smckusick */ 13326c50d0f2Smckusick SII_WAIT_UNTIL(cstat, regs->cstat, 13336c50d0f2Smckusick cstat & SII_CON, SII_WAIT_COUNT, i); 13346c50d0f2Smckusick if (!(cstat & SII_CON)) 13356c50d0f2Smckusick panic("sii resel"); 13366c50d0f2Smckusick /* FALLTHROUGH */ 13376c50d0f2Smckusick 13386c50d0f2Smckusick case SII_CON | SII_DST: 13396c50d0f2Smckusick /* 13406c50d0f2Smckusick * Its a reselection. Save the ID and wait for 13416c50d0f2Smckusick * interrupts to tell us what to do next 13426c50d0f2Smckusick * (should be MSG_IN of IDENTIFY). 13436c50d0f2Smckusick * NOTE: sc_target may be >= 0 if we were in 13446c50d0f2Smckusick * the process of trying to start a command 13456c50d0f2Smckusick * and were reselected before the select 13466c50d0f2Smckusick * command finished. 13476c50d0f2Smckusick */ 13486c50d0f2Smckusick sc->sc_target = i = regs->destat; 13496c50d0f2Smckusick regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE; 13506c50d0f2Smckusick MachEmptyWriteBuffer(); 13516c50d0f2Smckusick state = &sc->sc_st[i]; 13526c50d0f2Smckusick if (!state->prevComm) { 13536c50d0f2Smckusick printf("sii%d: device %d: spurrious reselection\n", 13546c50d0f2Smckusick sc - sii_softc, i); 13556c50d0f2Smckusick break; 13566c50d0f2Smckusick } 13576c50d0f2Smckusick state->prevComm = 0; 13586c50d0f2Smckusick #ifdef DEBUG 13596c50d0f2Smckusick if (sii_debug > 4) 13606c50d0f2Smckusick printf("resel %d ", sc->sc_target); 13616c50d0f2Smckusick #endif 13626c50d0f2Smckusick break; 13636c50d0f2Smckusick 13646c50d0f2Smckusick #ifdef notyet 13656c50d0f2Smckusick case SII_DST | SII_TGT: 13666c50d0f2Smckusick case SII_CON | SII_DST | SII_TGT: 13676c50d0f2Smckusick /* connected as target */ 13686c50d0f2Smckusick printf("sii%d: Selected by device %d as target!!\n", 13696c50d0f2Smckusick sc - sii_softc, regs->destat); 13706c50d0f2Smckusick regs->comm = SII_DISCON; 13716c50d0f2Smckusick MachEmptyWriteBuffer(); 13726c50d0f2Smckusick SII_WAIT_UNTIL(!(regs->cstat & SII_CON), 13736c50d0f2Smckusick SII_WAIT_COUNT, i); 13746c50d0f2Smckusick regs->cstat = 0xffff; 13756c50d0f2Smckusick regs->dstat = 0xffff; 13766c50d0f2Smckusick regs->comm = 0; 13776c50d0f2Smckusick break; 13786c50d0f2Smckusick #endif 13796c50d0f2Smckusick 13806c50d0f2Smckusick default: 13816c50d0f2Smckusick printf("sii%d: Unknown state change (cs %x)!!\n", 13826c50d0f2Smckusick sc - sii_softc, cstat); 13836c50d0f2Smckusick #ifdef DEBUG 13846c50d0f2Smckusick sii_DumpLog(); 13856c50d0f2Smckusick #endif 13866c50d0f2Smckusick } 13876c50d0f2Smckusick } 13886c50d0f2Smckusick 13896c50d0f2Smckusick /* 13906c50d0f2Smckusick * Read one byte of data. 13916c50d0f2Smckusick */ 13926c50d0f2Smckusick static int 13936c50d0f2Smckusick sii_GetByte(regs, phase) 13946c50d0f2Smckusick register SIIRegs *regs; 13956c50d0f2Smckusick int phase; 13966c50d0f2Smckusick { 13976c50d0f2Smckusick register unsigned dstat; 13986c50d0f2Smckusick register unsigned state; 13996c50d0f2Smckusick #ifdef PROGXFER 14006c50d0f2Smckusick register unsigned data; 14016c50d0f2Smckusick 14026c50d0f2Smckusick dstat = regs->dstat; 14036c50d0f2Smckusick state = regs->cstat & SII_STATE_MSK; 14046c50d0f2Smckusick regs->dmctrl = 0; 14056c50d0f2Smckusick if (!(dstat & SII_IBF) || (dstat & SII_MIS)) { 14066c50d0f2Smckusick regs->comm = state | phase; 14076c50d0f2Smckusick MachEmptyWriteBuffer(); 14086c50d0f2Smckusick /* wait a short time for IBF */ 14096c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF, 14106c50d0f2Smckusick SII_WAIT_COUNT, i); 14116c50d0f2Smckusick #ifdef DEBUG 14126c50d0f2Smckusick if (!(dstat & SII_IBF)) 14136c50d0f2Smckusick printf("status no IBF\n"); 14146c50d0f2Smckusick #endif 14156c50d0f2Smckusick } 14166c50d0f2Smckusick data = regs->data; 14176c50d0f2Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 14186c50d0f2Smckusick printf("sii_GetByte: DNE set 5\n"); 14196c50d0f2Smckusick sii_DumpLog(); 14206c50d0f2Smckusick regs->dstat = SII_DNE; 14216c50d0f2Smckusick } 14226c50d0f2Smckusick regs->comm = SII_INXFER | state | phase; 14236c50d0f2Smckusick MachEmptyWriteBuffer(); 14246c50d0f2Smckusick 14256c50d0f2Smckusick /* wait a short time for XFER complete */ 14266c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE, 14276c50d0f2Smckusick SII_WAIT_COUNT, i); 14286c50d0f2Smckusick 14296c50d0f2Smckusick if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) { 14306c50d0f2Smckusick #ifdef DEBUG 14316c50d0f2Smckusick if (sii_debug > 4) 14326c50d0f2Smckusick printf("cnt0 %d\n", i); 14336c50d0f2Smckusick #endif 14346c50d0f2Smckusick printf("MsgIn %x ?? ds %x cm %x i %d\n", 14356c50d0f2Smckusick data, dstat, comm, i); /* XXX */ 14366c50d0f2Smckusick sii_DumpLog(); /* XXX */ 14376c50d0f2Smckusick panic("status"); /* XXX */ 14386c50d0f2Smckusick goto again; 14396c50d0f2Smckusick } 14406c50d0f2Smckusick 14416c50d0f2Smckusick /* clear the DNE, other errors handled later */ 14426c50d0f2Smckusick regs->dstat = SII_DNE; 14436c50d0f2Smckusick MachEmptyWriteBuffer(); 14446c50d0f2Smckusick return (data); 14456c50d0f2Smckusick 14466c50d0f2Smckusick #else /* PROGXFER */ 14476c50d0f2Smckusick register int i; 14486c50d0f2Smckusick 14496c50d0f2Smckusick state = regs->cstat & SII_STATE_MSK; 14506c50d0f2Smckusick regs->dmctrl = 0; 14516c50d0f2Smckusick if (regs->dstat & SII_DNE) { 14526c50d0f2Smckusick printf("sii_GetByte: DNE cs %x ds %x cm %x\n", 14536c50d0f2Smckusick regs->cstat, regs->dstat, regs->comm); /* XXX */ 14546c50d0f2Smckusick regs->dstat = SII_DNE; 14556c50d0f2Smckusick } 14566c50d0f2Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 14576c50d0f2Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 14586c50d0f2Smckusick regs->dmlotc = 1; 14596c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | state | phase; 14606c50d0f2Smckusick MachEmptyWriteBuffer(); 14616c50d0f2Smckusick 14626c50d0f2Smckusick /* wait a short time for XFER complete */ 14636c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 14646c50d0f2Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 14656c50d0f2Smckusick SII_WAIT_COUNT, i); 14666c50d0f2Smckusick 14676c50d0f2Smckusick if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) { 14686c50d0f2Smckusick printf("sii_GetByte: ds %x cm %x i %d lotc %d\n", 14696c50d0f2Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 14706c50d0f2Smckusick sii_DumpLog(); /* XXX */ 14716c50d0f2Smckusick return (-1); 14726c50d0f2Smckusick } 14736c50d0f2Smckusick 14746c50d0f2Smckusick /* clear the DNE, other errors handled later */ 14756c50d0f2Smckusick regs->dstat = SII_DNE; 14766c50d0f2Smckusick MachEmptyWriteBuffer(); 14776c50d0f2Smckusick 14786c50d0f2Smckusick /* return one byte of data (optimized CopyFromBuffer()) */ 14796c50d0f2Smckusick return (*(volatile u_short *)SII_BUF_ADDR & 0xFF); 14806c50d0f2Smckusick #endif /* PROGXFER */ 14816c50d0f2Smckusick } 14826c50d0f2Smckusick 14836c50d0f2Smckusick /* 14846c50d0f2Smckusick * Exchange messages to initiate synchronous data transfers. 14856c50d0f2Smckusick */ 14866c50d0f2Smckusick static void 14876c50d0f2Smckusick sii_DoSync(regs, state) 14886c50d0f2Smckusick register SIIRegs *regs; 14896c50d0f2Smckusick register State *state; 14906c50d0f2Smckusick { 14916c50d0f2Smckusick register unsigned dstat; 14926c50d0f2Smckusick register int i; 14936c50d0f2Smckusick unsigned len; 14946c50d0f2Smckusick 14956c50d0f2Smckusick printf("sii_DoSync: per %d req/ack %d\n", 14966c50d0f2Smckusick sii_buf[3], sii_buf[4]); /* XXX */ 14976c50d0f2Smckusick len = sii_buf[4]; 14986c50d0f2Smckusick if (len > 3) 14996c50d0f2Smckusick len = 3; /* SII chip can only handle 3 max */ 15006c50d0f2Smckusick 15016c50d0f2Smckusick sii_buf[0] = SCSI_EXTENDED_MSG; 15026c50d0f2Smckusick sii_buf[1] = 3; /* message length */ 15036c50d0f2Smckusick sii_buf[2] = SCSI_SYNCHRONOUS_XFER; 15046c50d0f2Smckusick sii_buf[4] = len; 15056c50d0f2Smckusick CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5); 15066c50d0f2Smckusick regs->dmaddrl = ((unsigned)SII_BUF_ADDR >> 1); 15076c50d0f2Smckusick regs->dmaddrh = ((unsigned)SII_BUF_ADDR >> 17) & 03; 15086c50d0f2Smckusick regs->dmlotc = 5; 15096c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | SII_ATN | 15106c50d0f2Smckusick (regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE; 15116c50d0f2Smckusick MachEmptyWriteBuffer(); 15126c50d0f2Smckusick 15136c50d0f2Smckusick /* wait a short time for XFER complete */ 15146c50d0f2Smckusick SII_WAIT_UNTIL(dstat, regs->dstat, 15156c50d0f2Smckusick (dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ), 15166c50d0f2Smckusick SII_WAIT_COUNT, i); 15176c50d0f2Smckusick 15186c50d0f2Smckusick if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) { 15196c50d0f2Smckusick printf("sii_DoSync: ds %x cm %x i %d lotc %d\n", 15206c50d0f2Smckusick dstat, regs->comm, i, regs->dmlotc); /* XXX */ 15216c50d0f2Smckusick sii_DumpLog(); /* XXX */ 15226c50d0f2Smckusick return; 15236c50d0f2Smckusick } 15246c50d0f2Smckusick 15256c50d0f2Smckusick /* clear the DNE, other errors handled later */ 15266c50d0f2Smckusick regs->dstat = SII_DNE; 15276c50d0f2Smckusick regs->comm = regs->comm & SII_STATE_MSK; 15286c50d0f2Smckusick MachEmptyWriteBuffer(); 15296c50d0f2Smckusick 15306c50d0f2Smckusick state->dmaReqAck = len; 15316c50d0f2Smckusick } 15326c50d0f2Smckusick 15336c50d0f2Smckusick /* 15346c50d0f2Smckusick * Issue the sequence of commands to the controller to start DMA. 15356c50d0f2Smckusick * NOTE: the data buffer should be word-aligned for DMA out. 15366c50d0f2Smckusick */ 15376c50d0f2Smckusick static void 15386c50d0f2Smckusick sii_StartDMA(regs, phase, dmaAddr, size) 15396c50d0f2Smckusick register SIIRegs *regs; /* which SII to use */ 15406c50d0f2Smckusick int phase; /* phase to send/receive data */ 15416c50d0f2Smckusick u_short *dmaAddr; /* DMA buffer address */ 15426c50d0f2Smckusick int size; /* # of bytes to transfer */ 15436c50d0f2Smckusick { 15446c50d0f2Smckusick 15456c50d0f2Smckusick if (regs->dstat & SII_DNE) { /* XXX */ 15466c50d0f2Smckusick printf("sii_StartDMA: DNE set\n"); 15476c50d0f2Smckusick sii_DumpLog(); 15486c50d0f2Smckusick regs->dstat = SII_DNE; 15496c50d0f2Smckusick } 15506c50d0f2Smckusick regs->dmaddrl = ((unsigned)dmaAddr >> 1); 15516c50d0f2Smckusick regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03; 15526c50d0f2Smckusick regs->dmlotc = size; 15536c50d0f2Smckusick regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) | 15546c50d0f2Smckusick phase; 15556c50d0f2Smckusick MachEmptyWriteBuffer(); 15566c50d0f2Smckusick 15576c50d0f2Smckusick #ifdef DEBUG 15586c50d0f2Smckusick if (sii_debug > 5) { 15596c50d0f2Smckusick printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n", 15606c50d0f2Smckusick regs->cstat, regs->dstat, regs->comm, size); 15616c50d0f2Smckusick } 15626c50d0f2Smckusick #endif 15636c50d0f2Smckusick } 15646c50d0f2Smckusick 15656c50d0f2Smckusick /* 15666c50d0f2Smckusick * Call the device driver's 'done' routine to let it know the command is done. 15676c50d0f2Smckusick * The 'done' routine may try to start another command. 15686c50d0f2Smckusick * To be fair, we should start pending commands for other devices 15696c50d0f2Smckusick * before allowing the same device to start another command. 15706c50d0f2Smckusick */ 15716c50d0f2Smckusick static void 15726c50d0f2Smckusick sii_CmdDone(sc, target, error) 15736c50d0f2Smckusick register struct siisoftc *sc; /* which SII to use */ 15746c50d0f2Smckusick int target; /* which device is done */ 15756c50d0f2Smckusick int error; /* error code if any errors */ 15766c50d0f2Smckusick { 15776c50d0f2Smckusick register ScsiCmd *scsicmd; 15786c50d0f2Smckusick register int i; 15796c50d0f2Smckusick 15806c50d0f2Smckusick scsicmd = sc->sc_cmd[target]; 15816c50d0f2Smckusick #ifdef DIAGNOSTIC 15826c50d0f2Smckusick if (target < 0 || !scsicmd) 15836c50d0f2Smckusick panic("sii_CmdDone"); 15846c50d0f2Smckusick #endif 15856c50d0f2Smckusick sc->sc_cmd[target] = (ScsiCmd *)0; 15866c50d0f2Smckusick #ifdef DEBUG 15876c50d0f2Smckusick if (sii_debug > 1) { 15886c50d0f2Smckusick printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n", 15896c50d0f2Smckusick scsicmd->sd->sd_driver->d_name, target, 15906c50d0f2Smckusick scsicmd->cmd[0], error, sc->sc_st[target].buflen); 15916c50d0f2Smckusick } 15926c50d0f2Smckusick #endif 15936c50d0f2Smckusick 15946c50d0f2Smckusick /* look for another device that is ready */ 15956c50d0f2Smckusick for (i = 0; i < SII_NCMD; i++) { 15966c50d0f2Smckusick /* don't restart a disconnected command */ 15976c50d0f2Smckusick if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm) 15986c50d0f2Smckusick continue; 15996c50d0f2Smckusick sii_StartCmd(sc, i); 16006c50d0f2Smckusick break; 16016c50d0f2Smckusick } 16026c50d0f2Smckusick 16036c50d0f2Smckusick (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error, 16046c50d0f2Smckusick sc->sc_st[target].buflen, sc->sc_st[target].statusByte); 16056c50d0f2Smckusick } 16066c50d0f2Smckusick 16076c50d0f2Smckusick #ifdef DEBUG 16086c50d0f2Smckusick sii_DumpLog() 16096c50d0f2Smckusick { 16106c50d0f2Smckusick register struct sii_log *lp; 16116c50d0f2Smckusick 16126c50d0f2Smckusick printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn, 16136c50d0f2Smckusick sii_debug_sz); 16146c50d0f2Smckusick lp = sii_logp + 1; 16156c50d0f2Smckusick if (lp > &sii_log[NLOG]) 16166c50d0f2Smckusick lp = sii_log; 16176c50d0f2Smckusick while (lp != sii_logp) { 16186c50d0f2Smckusick printf("target %d cs %x ds %x cm %x msg %x\n", 16196c50d0f2Smckusick lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg); 16206c50d0f2Smckusick if (++lp >= &sii_log[NLOG]) 16216c50d0f2Smckusick lp = sii_log; 16226c50d0f2Smckusick } 16236c50d0f2Smckusick } 16246c50d0f2Smckusick #endif 16256c50d0f2Smckusick #endif 1626