xref: /original-bsd/sys/pmax/dev/sii.c (revision e9679b18)
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