xref: /original-bsd/sys/pmax/dev/sii.c (revision 95ecee29)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)sii.c	8.2 (Berkeley) 11/30/93
11  *
12  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devSII.c,
13  *	v 9.2 89/09/14 13:37:41 jhh Exp $ SPRITE (DECWRL)";
14  */
15 
16 #include "sii.h"
17 #if NSII > 0
18 /*
19  * SCSI interface driver
20  */
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/dkstat.h>
24 #include <sys/buf.h>
25 #include <sys/conf.h>
26 #include <sys/errno.h>
27 
28 #include <machine/machConst.h>
29 #include <pmax/dev/device.h>
30 #include <pmax/dev/scsi.h>
31 #include <pmax/dev/siireg.h>
32 
33 #include <pmax/pmax/kn01.h>
34 
35 int	siiprobe();
36 void	siistart();
37 struct	driver siidriver = {
38 	"sii", siiprobe, siistart, 0,
39 };
40 
41 typedef struct scsi_state {
42 	int	statusByte;	/* status byte returned during STATUS_PHASE */
43 	int	dmaDataPhase;	/* which data phase to expect */
44 	int	dmaCurPhase;	/* SCSI phase if DMA is in progress */
45 	int	dmaPrevPhase;	/* SCSI phase of DMA suspended by disconnect */
46 	u_short	*dmaAddr[2];	/* DMA buffer memory address */
47 	int	dmaBufIndex;	/* which of the above is currently in use */
48 	int	dmalen;		/* amount to transfer in this chunk */
49 	int	cmdlen;		/* total remaining amount of cmd to transfer */
50 	u_char	*cmd;		/* current pointer within scsicmd->cmd */
51 	int	buflen;		/* total remaining amount of data to transfer */
52 	char	*buf;		/* current pointer within scsicmd->buf */
53 	u_short	flags;		/* see below */
54 	u_short	prevComm;	/* command reg before disconnect */
55 	u_short	dmaCtrl;	/* DMA control register if disconnect */
56 	u_short	dmaAddrL;	/* DMA address register if disconnect */
57 	u_short	dmaAddrH;	/* DMA address register if disconnect */
58 	u_short	dmaCnt;		/* DMA count if disconnect */
59 	u_short	dmaByte;	/* DMA byte if disconnect on odd boundary */
60 	u_short	dmaReqAck;	/* DMA synchronous xfer offset or 0 if async */
61 } State;
62 
63 /* state flags */
64 #define FIRST_DMA	0x01	/* true if no data DMA started yet */
65 
66 #define SII_NCMD	7
67 struct siisoftc {
68 	SIIRegs	*sc_regs;		/* HW address of SII controller chip */
69 	int	sc_flags;
70 	int	sc_target;		/* target SCSI ID if connected */
71 	ScsiCmd	*sc_cmd[SII_NCMD];	/* active command indexed by ID */
72 	State	sc_st[SII_NCMD];	/* state info for each active command */
73 } sii_softc[NSII];
74 
75 /*
76  * MACROS for timing out spin loops.
77  *
78  * Wait until expression is true.
79  *
80  * Control register bits can change at any time so when the CPU
81  * reads a register, the bits might change and
82  * invalidate the setup and hold times for the CPU.
83  * This macro reads the register twice to be sure the value is stable.
84  *
85  *	args:	var 		- variable to save control register contents
86  *		reg		- control register to read
87  *		expr 		- expression to spin on
88  *		spincount 	- maximum number of times through the loop
89  *		cntr		- variable for number of tries
90  */
91 #define	SII_WAIT_UNTIL(var, reg, expr, spincount, cntr) {	\
92 		register unsigned tmp = reg;			\
93 		for (cntr = 0; cntr < spincount; cntr++) {	\
94 			while (tmp != (var = reg))		\
95 				tmp = var;			\
96 			if (expr)				\
97 				break;				\
98 			if (cntr >= 100)			\
99 				DELAY(100);			\
100 		}						\
101 	}
102 
103 #ifdef DEBUG
104 int	sii_debug = 1;
105 int	sii_debug_cmd;
106 int	sii_debug_bn;
107 int	sii_debug_sz;
108 #define NLOG 16
109 struct sii_log {
110 	u_short	cstat;
111 	u_short	dstat;
112 	u_short	comm;
113 	u_short	msg;
114 	int	target;
115 } sii_log[NLOG], *sii_logp = sii_log;
116 #endif
117 
118 u_char	sii_buf[256];	/* used for extended messages */
119 
120 #define NORESET	0
121 #define RESET	1
122 #define NOWAIT	0
123 #define WAIT	1
124 
125 /* define a safe address in the SCSI buffer for doing status & message DMA */
126 #define SII_BUF_ADDR	(MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) \
127 		+ SII_MAX_DMA_XFER_LENGTH * 14)
128 
129 static void sii_Reset();
130 static void sii_StartCmd();
131 static void sii_CmdDone();
132 static void sii_DoIntr();
133 static void sii_StateChg();
134 static void sii_DoSync();
135 static void sii_StartDMA();
136 static int sii_GetByte();
137 
138 /*
139  * Test to see if device is present.
140  * Return true if found and initialized ok.
141  */
142 siiprobe(cp)
143 	register struct pmax_ctlr *cp;
144 {
145 	register struct siisoftc *sc;
146 	register int i;
147 
148 	if (cp->pmax_unit >= NSII)
149 		return (0);
150 	sc = &sii_softc[cp->pmax_unit];
151 	sc->sc_regs = (SIIRegs *)cp->pmax_addr;
152 	sc->sc_flags = cp->pmax_flags;
153 	sc->sc_target = -1;	/* no command active */
154 	/*
155 	 * Give each target its own DMA buffer region.
156 	 * Make it big enough for 2 max transfers so we can ping pong buffers
157 	 * while we copy the data.
158 	 */
159 	for (i = 0; i < SII_NCMD; i++) {
160 		sc->sc_st[i].dmaAddr[0] = (u_short *)
161 			MACH_PHYS_TO_UNCACHED(KN01_SYS_SII_B_START) +
162 			2 * SII_MAX_DMA_XFER_LENGTH * i;
163 		sc->sc_st[i].dmaAddr[1] = sc->sc_st[i].dmaAddr[0] +
164 			SII_MAX_DMA_XFER_LENGTH;
165 	}
166 
167 	printf("sii%d at nexus0 csr 0x%x\n", cp->pmax_unit, cp->pmax_addr);
168 	sii_Reset(sc->sc_regs, RESET);
169 	return (1);
170 }
171 
172 /*
173  * Start activity on a SCSI device.
174  * We maintain information on each device separately since devices can
175  * connect/disconnect during an operation.
176  */
177 void
178 siistart(scsicmd)
179 	register ScsiCmd *scsicmd;	/* command to start */
180 {
181 	register struct scsi_device *sdp = scsicmd->sd;
182 	register struct siisoftc *sc = &sii_softc[sdp->sd_ctlr];
183 	int s;
184 
185 	s = splbio();
186 	/*
187 	 * Check if another command is already in progress.
188 	 * We may have to change this if we allow SCSI devices with
189 	 * separate LUNs.
190 	 */
191 	if (sc->sc_cmd[sdp->sd_drive]) {
192 		printf("sii%d: device %s busy at start\n", sdp->sd_ctlr,
193 			sdp->sd_driver->d_name);
194 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
195 			scsicmd->buflen, 0);
196 		splx(s);
197 	}
198 	sc->sc_cmd[sdp->sd_drive] = scsicmd;
199 	sii_StartCmd(sc, sdp->sd_drive);
200 	splx(s);
201 }
202 
203 /*
204  * Check to see if any SII chips have pending interrupts
205  * and process as appropriate.
206  */
207 void
208 siiintr(unit)
209 	int unit;
210 {
211 	register struct siisoftc *sc = &sii_softc[unit];
212 	unsigned dstat;
213 
214 	/*
215 	 * Find which controller caused the interrupt.
216 	 */
217 	dstat = sc->sc_regs->dstat;
218 	if (dstat & (SII_CI | SII_DI))
219 		sii_DoIntr(sc, dstat);
220 }
221 
222 /*
223  * Reset the SII chip and do a SCSI reset if 'reset' is true.
224  * NOTE: if !cold && reset, should probably probe for devices
225  * since a SCSI bus reset will set UNIT_ATTENTION.
226  */
227 static void
228 sii_Reset(regs, reset)
229 	register SIIRegs *regs;
230 	int reset;				/* TRUE => reset SCSI bus */
231 {
232 
233 #ifdef DEBUG
234 	if (sii_debug > 1)
235 		printf("sii: RESET\n");
236 #endif
237 	/*
238 	 * Reset the SII chip.
239 	 */
240 	regs->comm = SII_CHRESET;
241 	/*
242 	 * Set arbitrated bus mode.
243 	 */
244 	regs->csr = SII_HPM;
245 	/*
246 	 * SII is always ID 7.
247 	 */
248 	regs->id = SII_ID_IO | 7;
249 	/*
250 	 * Enable SII to drive the SCSI bus.
251 	 */
252 	regs->dictrl = SII_PRE;
253 	regs->dmctrl = 0;
254 
255 	if (reset) {
256 		register int i;
257 
258 		/*
259 		 * Assert SCSI bus reset for at least 25 Usec to clear the
260 		 * world. SII_DO_RST is self clearing.
261 		 * Delay 250 ms before doing any commands.
262 		 */
263 		regs->comm = SII_DO_RST;
264 		MachEmptyWriteBuffer();
265 		DELAY(250000);
266 
267 		/* rearbitrate synchronous offset */
268 		for (i = 0; i < SII_NCMD; i++)
269 			sii_softc[0].sc_st[i].dmaReqAck = 0;
270 	}
271 
272 	/*
273 	 * Clear any pending interrupts from the reset.
274 	 */
275 	regs->cstat = regs->cstat;
276 	regs->dstat = regs->dstat;
277 	/*
278 	 * Set up SII for arbitrated bus mode, SCSI parity checking,
279 	 * Reselect Enable, and Interrupt Enable.
280 	 */
281 	regs->csr = SII_HPM | SII_RSE | SII_PCE | SII_IE;
282 	MachEmptyWriteBuffer();
283 }
284 
285 /*
286  * Start a SCSI command by sending the cmd data
287  * to a SCSI controller via the SII.
288  * Call the device done proceedure if it can't be started.
289  * NOTE: we should be called with interrupts disabled.
290  */
291 static void
292 sii_StartCmd(sc, target)
293 	register struct siisoftc *sc;	/* which SII to use */
294 	register int target;		/* which command to start */
295 {
296 	register SIIRegs *regs;
297 	register ScsiCmd *scsicmd;
298 	register State *state;
299 	register unsigned status;
300 	int error, retval;
301 
302 	/* if another command is currently in progress, just wait */
303 	if (sc->sc_target >= 0)
304 		return;
305 
306 	/* initialize state information for this command */
307 	scsicmd = sc->sc_cmd[target];
308 	state = &sc->sc_st[target];
309 	state->flags = FIRST_DMA;
310 	state->prevComm = 0;
311 	state->dmalen = 0;
312 	state->dmaCurPhase = -1;
313 	state->dmaPrevPhase = -1;
314 	state->dmaBufIndex = 0;
315 	state->cmd = scsicmd->cmd;
316 	state->cmdlen = scsicmd->cmdlen;
317 	if ((state->buflen = scsicmd->buflen) == 0) {
318 		state->dmaDataPhase = -1; /* illegal phase. shouldn't happen */
319 		state->buf = (char *)0;
320 	} else {
321 		state->dmaDataPhase =
322 			(scsicmd->flags & SCSICMD_DATA_TO_DEVICE) ?
323 			SII_DATA_OUT_PHASE : SII_DATA_IN_PHASE;
324 		state->buf = scsicmd->buf;
325 	}
326 
327 #ifdef DEBUG
328 	if (sii_debug > 1) {
329 		printf("sii_StartCmd: %s target %d cmd 0x%x addr %x size %d dma %d\n",
330 			scsicmd->sd->sd_driver->d_name, target,
331 			scsicmd->cmd[0], scsicmd->buf, scsicmd->buflen,
332 			state->dmaDataPhase);
333 	}
334 	sii_debug_cmd = scsicmd->cmd[0];
335 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
336 		sii_debug_bn = (scsicmd->cmd[2] << 24) |
337 			(scsicmd->cmd[3] << 16) |
338 			(scsicmd->cmd[4] << 8) |
339 			scsicmd->cmd[5];
340 		sii_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
341 	}
342 #endif
343 
344 	/* try to select the target */
345 	regs = sc->sc_regs;
346 
347 	/*
348 	 * Another device may have selected us; in which case,
349 	 * this command will be restarted later.
350 	 */
351 	if ((status = regs->dstat) & (SII_CI | SII_DI)) {
352 		sii_DoIntr(sc, status);
353 		return;
354 	}
355 
356 	sc->sc_target = target;
357 	if (scsicmd->flags & SCSICMD_USE_SYNC) {
358 		printf("sii_StartCmd: doing extended msg\n"); /* XXX */
359 		/*
360 		 * Setup to send both the identify message and the synchronous
361 		 * data transfer request.
362 		 */
363 		sii_buf[0] = SCSI_DIS_REC_IDENTIFY;
364 		sii_buf[1] = SCSI_EXTENDED_MSG;
365 		sii_buf[2] = 3;		/* message length */
366 		sii_buf[3] = SCSI_SYNCHRONOUS_XFER;
367 		sii_buf[4] = 0;
368 		sii_buf[5] = 3;		/* maximum SII chip supports */
369 
370 		state->dmaCurPhase = SII_MSG_OUT_PHASE,
371 		state->dmalen = 6;
372 		CopyToBuffer((u_short *)sii_buf,
373 			(volatile u_short *)SII_BUF_ADDR, 6);
374 		regs->slcsr = target;
375 		regs->dmctrl = 0;
376 		regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1);
377 		regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03;
378 		regs->dmlotc = 6;
379 		regs->comm = SII_DMA | SII_INXFER | SII_SELECT | SII_ATN |
380 			SII_CON | SII_MSG_OUT_PHASE;
381 	} else {
382 		/* do a chained, select with ATN and programmed I/O command */
383 		regs->data = SCSI_DIS_REC_IDENTIFY;
384 		regs->slcsr = target;
385 		regs->dmctrl = 0;
386 		regs->comm = SII_INXFER | SII_SELECT | SII_ATN | SII_CON |
387 			SII_MSG_OUT_PHASE;
388 	}
389 	MachEmptyWriteBuffer();
390 
391 	/*
392 	 * Wait for something to happen
393 	 * (should happen soon or we would use interrupts).
394 	 */
395 	SII_WAIT_UNTIL(status, regs->cstat, status & (SII_CI | SII_DI),
396 		SII_WAIT_COUNT/4, retval);
397 
398 	/* check to see if we are connected OK */
399 	if ((status & (SII_RST | SII_SCH | SII_STATE_MSK)) ==
400 	    (SII_SCH | SII_CON)) {
401 		regs->cstat = status;
402 		MachEmptyWriteBuffer();
403 
404 #ifdef DEBUG
405 		sii_logp->target = target;
406 		sii_logp->cstat = status;
407 		sii_logp->dstat = 0;
408 		sii_logp->comm = regs->comm;
409 		sii_logp->msg = -1;
410 		if (++sii_logp >= &sii_log[NLOG])
411 			sii_logp = sii_log;
412 #endif
413 
414 		/* wait a short time for command phase */
415 		SII_WAIT_UNTIL(status, regs->dstat, status & SII_MIS,
416 			SII_WAIT_COUNT, retval);
417 #ifdef DEBUG
418 		if (sii_debug > 2)
419 			printf("sii_StartCmd: ds %x cnt %d\n", status, retval);
420 #endif
421 		if ((status & (SII_CI | SII_MIS | SII_PHASE_MSK)) !=
422 		    (SII_MIS | SII_CMD_PHASE)) {
423 			printf("sii_StartCmd: timeout cs %x ds %x cnt %d\n",
424 				regs->cstat, status, retval); /* XXX */
425 			/* process interrupt or continue until it happens */
426 			if (status & (SII_CI | SII_DI))
427 				sii_DoIntr(sc, status);
428 			return;
429 		}
430 		regs->dstat = SII_DNE;	/* clear Msg Out DMA done */
431 
432 		/* send command data */
433 		CopyToBuffer((u_short *)state->cmd,
434 			(volatile u_short *)state->dmaAddr[0], state->cmdlen);
435 		sii_StartDMA(regs, state->dmaCurPhase = SII_CMD_PHASE,
436 			state->dmaAddr[0], state->dmalen = scsicmd->cmdlen);
437 
438 		/* wait a little while for DMA to finish */
439 		SII_WAIT_UNTIL(status, regs->dstat, status & (SII_CI | SII_DI),
440 			SII_WAIT_COUNT, retval);
441 #ifdef DEBUG
442 		if (sii_debug > 2)
443 			printf("sii_StartCmd: ds %x, cnt %d\n", status, retval);
444 #endif
445 		if (status & (SII_CI | SII_DI))
446 			sii_DoIntr(sc, status);
447 #ifdef DEBUG
448 		if (sii_debug > 2)
449 			printf("sii_StartCmd: DONE ds %x\n", regs->dstat);
450 #endif
451 		return;
452 	}
453 
454 	/*
455 	 * Another device may have selected us; in which case,
456 	 * this command will be restarted later.
457 	 */
458 	if (status & (SII_CI | SII_DI)) {
459 		sii_DoIntr(sc, regs->dstat);
460 		return;
461 	}
462 
463 	/*
464 	 * Disconnect if selection command still in progress.
465 	 */
466 	if (status & SII_SIP) {
467 		error = ENXIO;	/* device didn't respond */
468 		regs->comm = SII_DISCON;
469 		MachEmptyWriteBuffer();
470 		SII_WAIT_UNTIL(status, regs->cstat,
471 			!(status & (SII_CON | SII_SIP)),
472 			SII_WAIT_COUNT, retval);
473 	} else
474 		error = EBUSY;	/* couldn't get the bus */
475 #ifdef DEBUG
476 	if (sii_debug > 1)
477 		printf("sii_StartCmd: Couldn't select target %d error %d\n",
478 			target, error);
479 #endif
480 	sc->sc_target = -1;
481 	regs->cstat = 0xffff;
482 	regs->dstat = 0xffff;
483 	regs->comm = 0;
484 	MachEmptyWriteBuffer();
485 	sii_CmdDone(sc, target, error);
486 }
487 
488 /*
489  * Process interrupt conditions.
490  */
491 static void
492 sii_DoIntr(sc, dstat)
493 	register struct siisoftc *sc;
494 	register unsigned dstat;
495 {
496 	register SIIRegs *regs = sc->sc_regs;
497 	register State *state;
498 	register unsigned cstat;
499 	register int i;
500 	unsigned comm, msg;
501 
502 again:
503 	comm = regs->comm;
504 
505 #ifdef DEBUG
506 	if (sii_debug > 3)
507 		printf("sii_DoIntr: cs %x, ds %x cm %x ",
508 			regs->cstat, dstat, comm);
509 	sii_logp->target = sc->sc_target;
510 	sii_logp->cstat = regs->cstat;
511 	sii_logp->dstat = dstat;
512 	sii_logp->comm = comm;
513 	sii_logp->msg = -1;
514 	if (++sii_logp >= &sii_log[NLOG])
515 		sii_logp = sii_log;
516 #endif
517 
518 	regs->dstat = dstat;	/* acknowledge everything */
519 	MachEmptyWriteBuffer();
520 
521 	if (dstat & SII_CI) {
522 		/* deglitch cstat register */
523 		msg = regs->cstat;
524 		while (msg != (cstat = regs->cstat))
525 			msg = cstat;
526 		regs->cstat = cstat;	/* acknowledge everything */
527 		MachEmptyWriteBuffer();
528 #ifdef DEBUG
529 		if (sii_logp > sii_log)
530 			sii_logp[-1].cstat = cstat;
531 		else
532 			sii_log[NLOG - 1].cstat = cstat;
533 #endif
534 
535 		/* check for a BUS RESET */
536 		if (cstat & SII_RST) {
537 			printf("sii%d: SCSI bus reset!!\n", sc - sii_softc);
538 			/* need to flush disconnected commands */
539 			for (i = 0; i < SII_NCMD; i++) {
540 				if (!sc->sc_cmd[i])
541 					continue;
542 				sii_CmdDone(sc, i, EIO);
543 			}
544 			/* rearbitrate synchronous offset */
545 			for (i = 0; i < SII_NCMD; i++)
546 				sc->sc_st[i].dmaReqAck = 0;
547 			sc->sc_target = -1;
548 			return;
549 		}
550 
551 #ifdef notdef
552 		/*
553 		 * Check for a BUS ERROR.
554 		 * According to DEC, this feature doesn't really work
555 		 * and to just clear the bit if it's set.
556 		 */
557 		if (cstat & SII_BER) {
558 		}
559 #endif
560 
561 		/* check for state change */
562 		if (cstat & SII_SCH) {
563 			sii_StateChg(sc, cstat);
564 			comm = regs->comm;
565 		}
566 	}
567 
568 	/* check for DMA completion */
569 	if (dstat & SII_DNE) {
570 		u_short *dma;
571 		char *buf;
572 
573 		/* check for a PARITY ERROR */
574 		if (dstat & SII_IPE) {
575 			printf("sii%d: Parity error!!\n", sc - sii_softc);
576 			goto abort;
577 		}
578 		/*
579 		 * There is a race condition with SII_SCH. There is a short
580 		 * window between the time a SII_SCH is seen after a disconnect
581 		 * and when the SII_SCH is cleared. A reselect can happen
582 		 * in this window and we will clear the SII_SCH without
583 		 * processing the reconnect.
584 		 */
585 		if (sc->sc_target < 0) {
586 			cstat = regs->cstat;
587 			printf("sii%d: target %d DNE?? dev %d,%d cs %x\n",
588 				sc - sii_softc, sc->sc_target,
589 				regs->slcsr, regs->destat,
590 				cstat); /* XXX */
591 			if (cstat & SII_DST) {
592 				sc->sc_target = regs->destat;
593 				state->prevComm = 0;
594 			} else
595 				panic("sc_target 1");
596 		}
597 		state = &sc->sc_st[sc->sc_target];
598 		/* dmalen = amount left to transfer, i = amount transfered */
599 		i = state->dmalen;
600 		state->dmalen = 0;
601 		state->dmaCurPhase = -1;
602 #ifdef DEBUG
603 		if (sii_debug > 4) {
604 			printf("DNE: amt %d ", i);
605 			if (!(dstat & SII_TCZ))
606 				printf("no TCZ?? (%d) ", regs->dmlotc);
607 		} else if (!(dstat & SII_TCZ)) {
608 			printf("sii%d: device %d: no TCZ?? (%d)\n",
609 				sc - sii_softc, sc->sc_target, regs->dmlotc);
610 			sii_DumpLog(); /* XXX */
611 		}
612 #endif
613 		switch (comm & SII_PHASE_MSK) {
614 		case SII_CMD_PHASE:
615 			state->cmdlen -= i;
616 			break;
617 
618 		case SII_DATA_IN_PHASE:
619 			/* check for more data for the same phase */
620 			dma = state->dmaAddr[state->dmaBufIndex];
621 			buf = state->buf;
622 			state->buf += i;
623 			state->buflen -= i;
624 			if (state->buflen > 0 && !(dstat & SII_MIS)) {
625 				int len;
626 
627 				/* start reading next chunk */
628 				len = state->buflen;
629 				if (len > SII_MAX_DMA_XFER_LENGTH)
630 					len = SII_MAX_DMA_XFER_LENGTH;
631 				state->dmaBufIndex = !state->dmaBufIndex;
632 				sii_StartDMA(regs,
633 					state->dmaCurPhase = SII_DATA_IN_PHASE,
634 					state->dmaAddr[state->dmaBufIndex],
635 					state->dmalen = len);
636 				dstat &= ~(SII_IBF | SII_TBE);
637 			}
638 			/* copy in the data */
639 			CopyFromBuffer((volatile u_short *)dma, buf, i);
640 			break;
641 
642 		case SII_DATA_OUT_PHASE:
643 			state->dmaBufIndex = !state->dmaBufIndex;
644 			state->buf += i;
645 			state->buflen -= i;
646 
647 			/* check for more data for the same phase */
648 			if (state->buflen <= 0 || (dstat & SII_MIS))
649 				break;
650 
651 			/* start next chunk */
652 			i = state->buflen;
653 			if (i > SII_MAX_DMA_XFER_LENGTH) {
654 				sii_StartDMA(regs, state->dmaCurPhase =
655 					SII_DATA_OUT_PHASE,
656 					state->dmaAddr[state->dmaBufIndex],
657 					state->dmalen =
658 					SII_MAX_DMA_XFER_LENGTH);
659 				/* prepare for next chunk */
660 				i -= SII_MAX_DMA_XFER_LENGTH;
661 				if (i > SII_MAX_DMA_XFER_LENGTH)
662 					i = SII_MAX_DMA_XFER_LENGTH;
663 				CopyToBuffer((u_short *)(state->buf +
664 					SII_MAX_DMA_XFER_LENGTH),
665 					(volatile u_short *)
666 					state->dmaAddr[!state->dmaBufIndex], i);
667 			} else {
668 				sii_StartDMA(regs, state->dmaCurPhase =
669 					SII_DATA_OUT_PHASE,
670 					state->dmaAddr[state->dmaBufIndex],
671 					state->dmalen = i);
672 			}
673 			dstat &= ~(SII_IBF | SII_TBE);
674 			break;
675 
676 		default:
677 			printf("sii%d: device %d: unexpected DNE\n",
678 				sc - sii_softc, sc->sc_target);
679 #ifdef DEBUG
680 			sii_DumpLog();
681 #endif
682 		}
683 	}
684 
685 	/* check for phase change or another MsgIn/Out */
686 	if (dstat & (SII_MIS | SII_IBF | SII_TBE)) {
687 		/*
688 		 * There is a race condition with SII_SCH. There is a short
689 		 * window between the time a SII_SCH is seen after a disconnect
690 		 * and when the SII_SCH is cleared. A reselect can happen
691 		 * in this window and we will clear the SII_SCH without
692 		 * processing the reconnect.
693 		 */
694 		if (sc->sc_target < 0) {
695 			cstat = regs->cstat;
696 			printf("sii%d: target %d MIS?? dev %d,%d cs %x ds %x\n",
697 				sc - sii_softc, sc->sc_target,
698 				regs->slcsr, regs->destat,
699 				cstat, dstat); /* XXX */
700 			if (cstat & SII_DST) {
701 				sc->sc_target = regs->destat;
702 				state->prevComm = 0;
703 			} else
704 				panic("sc_target 2");
705 		}
706 		state = &sc->sc_st[sc->sc_target];
707 		switch (dstat & SII_PHASE_MSK) {
708 		case SII_CMD_PHASE:
709 			if (state->dmaPrevPhase >= 0) {
710 				/* restart DMA after disconnect/reconnect */
711 				if (state->dmaPrevPhase != SII_CMD_PHASE) {
712 					printf("sii%d: device %d: dma reselect phase doesn't match\n",
713 						sc - sii_softc, sc->sc_target);
714 					goto abort;
715 				}
716 				state->dmaCurPhase = SII_CMD_PHASE;
717 				state->dmaPrevPhase = -1;
718 				regs->dmaddrl = state->dmaAddrL;
719 				regs->dmaddrh = state->dmaAddrH;
720 				regs->dmlotc = state->dmaCnt;
721 				if (state->dmaCnt & 1)
722 					regs->dmabyte = state->dmaByte;
723 				regs->comm = SII_DMA | SII_INXFER |
724 					(comm & SII_STATE_MSK) | SII_CMD_PHASE;
725 				MachEmptyWriteBuffer();
726 #ifdef DEBUG
727 				if (sii_debug > 4)
728 					printf("Cmd dcnt %d dadr %x ",
729 						state->dmaCnt,
730 						(state->dmaAddrH << 16) |
731 							state->dmaAddrL);
732 #endif
733 			} else {
734 				/* send command data */
735 				i = state->cmdlen;
736 				if (i == 0) {
737 					printf("sii%d: device %d: cmd count exceeded\n",
738 						sc - sii_softc, sc->sc_target);
739 					goto abort;
740 				}
741 				CopyToBuffer((u_short *)state->cmd,
742 					(volatile u_short *)state->dmaAddr[0],
743 					i);
744 				sii_StartDMA(regs, state->dmaCurPhase =
745 					SII_CMD_PHASE, state->dmaAddr[0],
746 					state->dmalen = i);
747 			}
748 			/* wait a short time for XFER complete */
749 			SII_WAIT_UNTIL(dstat, regs->dstat,
750 				dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
751 			if (dstat & (SII_CI | SII_DI)) {
752 #ifdef DEBUG
753 				if (sii_debug > 4)
754 					printf("cnt %d\n", i);
755 				else if (sii_debug > 0)
756 					printf("sii_DoIntr: cmd wait ds %x cnt %d\n",
757 						dstat, i);
758 #endif
759 				goto again;
760 			}
761 			break;
762 
763 		case SII_DATA_IN_PHASE:
764 		case SII_DATA_OUT_PHASE:
765 			regs->dmctrl = state->dmaReqAck;
766 			if (state->cmdlen > 0) {
767 				printf("sii%d: device %d: cmd %x: command data not all sent (%d) 1\n",
768 					sc - sii_softc, sc->sc_target,
769 					sc->sc_cmd[sc->sc_target]->cmd[0],
770 					state->cmdlen);
771 				state->cmdlen = 0;
772 #ifdef DEBUG
773 				sii_DumpLog();
774 #endif
775 			}
776 			if (state->dmaPrevPhase >= 0) {
777 				/* restart DMA after disconnect/reconnect */
778 				if (state->dmaPrevPhase !=
779 				    (dstat & SII_PHASE_MSK)) {
780 					printf("sii%d: device %d: dma reselect phase doesn't match\n",
781 						sc - sii_softc, sc->sc_target);
782 					goto abort;
783 				}
784 				state->dmaCurPhase = state->dmaPrevPhase;
785 				state->dmaPrevPhase = -1;
786 				regs->dmaddrl = state->dmaAddrL;
787 				regs->dmaddrh = state->dmaAddrH;
788 				regs->dmlotc = state->dmaCnt;
789 				if (state->dmaCnt & 1)
790 					regs->dmabyte = state->dmaByte;
791 				regs->comm = SII_DMA | SII_INXFER |
792 					(comm & SII_STATE_MSK) |
793 					state->dmaCurPhase;
794 				MachEmptyWriteBuffer();
795 #ifdef DEBUG
796 				if (sii_debug > 4)
797 					printf("Data %d dcnt %d dadr %x ",
798 						state->dmaDataPhase,
799 						state->dmaCnt,
800 						(state->dmaAddrH << 16) |
801 							state->dmaAddrL);
802 #endif
803 				break;
804 			}
805 			if (state->dmaDataPhase != (dstat & SII_PHASE_MSK)) {
806 				printf("sii%d: device %d: cmd %x: dma phase doesn't match\n",
807 					sc - sii_softc, sc->sc_target,
808 					sc->sc_cmd[sc->sc_target]->cmd[0]);
809 				goto abort;
810 			}
811 #ifdef DEBUG
812 			if (sii_debug > 4) {
813 				printf("Data %d ", state->dmaDataPhase);
814 				if (sii_debug > 5)
815 					printf("\n");
816 			}
817 #endif
818 			i = state->buflen;
819 			if (i == 0) {
820 				printf("sii%d: device %d: data count exceeded\n",
821 					sc - sii_softc, sc->sc_target);
822 				goto abort;
823 			}
824 			if (i > SII_MAX_DMA_XFER_LENGTH)
825 				i = SII_MAX_DMA_XFER_LENGTH;
826 			if ((dstat & SII_PHASE_MSK) == SII_DATA_IN_PHASE) {
827 				sii_StartDMA(regs,
828 					state->dmaCurPhase = SII_DATA_IN_PHASE,
829 					state->dmaAddr[state->dmaBufIndex],
830 					state->dmalen = i);
831 				break;
832 			}
833 			/* start first chunk */
834 			if (state->flags & FIRST_DMA) {
835 				state->flags &= ~FIRST_DMA;
836 				CopyToBuffer((u_short *)state->buf,
837 					(volatile u_short *)
838 					state->dmaAddr[state->dmaBufIndex], i);
839 			}
840 			sii_StartDMA(regs,
841 				state->dmaCurPhase = SII_DATA_OUT_PHASE,
842 				state->dmaAddr[state->dmaBufIndex],
843 				state->dmalen = i);
844 			i = state->buflen - SII_MAX_DMA_XFER_LENGTH;
845 			if (i > 0) {
846 				/* prepare for next chunk */
847 				if (i > SII_MAX_DMA_XFER_LENGTH)
848 					i = SII_MAX_DMA_XFER_LENGTH;
849 				CopyToBuffer((u_short *)(state->buf +
850 					SII_MAX_DMA_XFER_LENGTH),
851 					(volatile u_short *)
852 					state->dmaAddr[!state->dmaBufIndex], i);
853 			}
854 			break;
855 
856 		case SII_STATUS_PHASE:
857 			if (state->cmdlen > 0) {
858 				printf("sii%d: device %d: cmd %x: command data not all sent (%d) 2\n",
859 					sc - sii_softc, sc->sc_target,
860 					sc->sc_cmd[sc->sc_target]->cmd[0],
861 					state->cmdlen);
862 				state->cmdlen = 0;
863 #ifdef DEBUG
864 				sii_DumpLog();
865 #endif
866 			}
867 
868 			/* read amount transfered if DMA didn't finish */
869 			if (state->dmalen > 0) {
870 				i = state->dmalen - regs->dmlotc;
871 				state->dmalen = 0;
872 				state->dmaCurPhase = -1;
873 				regs->dmlotc = 0;
874 				regs->comm = comm &
875 					(SII_STATE_MSK | SII_PHASE_MSK);
876 				MachEmptyWriteBuffer();
877 				regs->dstat = SII_DNE;
878 				MachEmptyWriteBuffer();
879 #ifdef DEBUG
880 				if (sii_debug > 4)
881 					printf("DMA amt %d ", i);
882 #endif
883 				switch (comm & SII_PHASE_MSK) {
884 				case SII_DATA_IN_PHASE:
885 					/* copy in the data */
886 					CopyFromBuffer((volatile u_short *)
887 					    state->dmaAddr[state->dmaBufIndex],
888 					    state->buf, i);
889 
890 				case SII_CMD_PHASE:
891 				case SII_DATA_OUT_PHASE:
892 					state->buflen -= i;
893 				}
894 			}
895 
896 			/* read a one byte status message */
897 			state->statusByte = msg =
898 				sii_GetByte(regs, SII_STATUS_PHASE);
899 			if (msg < 0) {
900 				dstat = regs->dstat;
901 				goto again;
902 			}
903 #ifdef DEBUG
904 			if (sii_debug > 4)
905 				printf("Status %x ", msg);
906 			if (sii_logp > sii_log)
907 				sii_logp[-1].msg = msg;
908 			else
909 				sii_log[NLOG - 1].msg = msg;
910 #endif
911 
912 			/* do a quick wait for COMMAND_COMPLETE */
913 			SII_WAIT_UNTIL(dstat, regs->dstat,
914 				dstat & (SII_CI | SII_DI), SII_WAIT_COUNT, i);
915 			if (dstat & (SII_CI | SII_DI)) {
916 #ifdef DEBUG
917 				if (sii_debug > 4)
918 					printf("cnt2 %d\n", i);
919 #endif
920 				goto again;
921 			}
922 			break;
923 
924 		case SII_MSG_IN_PHASE:
925 			/*
926 			 * Save DMA state if DMA didn't finish.
927 			 * Be careful not to save state again after reconnect
928 			 * and see RESTORE_POINTER message.
929 			 * Note that the SII DMA address is not incremented
930 			 * as DMA proceeds.
931 			 */
932 			if (state->dmaCurPhase > 0) {
933 				/* save dma registers */
934 				state->dmaPrevPhase = state->dmaCurPhase;
935 				state->dmaCurPhase = -1;
936 				state->dmaCnt = i = regs->dmlotc;
937 				if (dstat & SII_OBB)
938 					state->dmaByte = regs->dmabyte;
939 				if (i == 0)
940 					i = SII_MAX_DMA_XFER_LENGTH;
941 				i = state->dmalen - i;
942 				/* note: no carry from dmaddrl to dmaddrh */
943 				state->dmaAddrL = regs->dmaddrl + i;
944 				state->dmaAddrH = regs->dmaddrh;
945 				regs->comm = comm &
946 					(SII_STATE_MSK | SII_PHASE_MSK);
947 				MachEmptyWriteBuffer();
948 				regs->dstat = SII_DNE;
949 				MachEmptyWriteBuffer();
950 #ifdef DEBUG
951 				if (sii_debug > 4) {
952 					printf("SavP dcnt %d dadr %x ",
953 						state->dmaCnt,
954 						(state->dmaAddrH << 16) |
955 						state->dmaAddrL);
956 					if (((dstat & SII_OBB) != 0) ^
957 					    (state->dmaCnt & 1))
958 						printf("OBB??? ");
959 				} else if (sii_debug > 0) {
960 					if (((dstat & SII_OBB) != 0) ^
961 					    (state->dmaCnt & 1)) {
962 						printf("sii_DoIntr: OBB??? ds %x cnt %d\n",
963 							dstat, state->dmaCnt);
964 						sii_DumpLog();
965 					}
966 				}
967 #endif
968 			}
969 
970 			/* read a one byte message */
971 			msg = sii_GetByte(regs, SII_MSG_IN_PHASE);
972 			if (msg < 0) {
973 				dstat = regs->dstat;
974 				goto again;
975 			}
976 #ifdef DEBUG
977 			if (sii_debug > 4)
978 				printf("MsgIn %x ", msg);
979 			if (sii_logp > sii_log)
980 				sii_logp[-1].msg = msg;
981 			else
982 				sii_log[NLOG - 1].msg = msg;
983 #endif
984 
985 			/* process message */
986 			switch (msg) {
987 			case SCSI_COMMAND_COMPLETE:
988 				msg = sc->sc_target;
989 				sc->sc_target = -1;
990 				/*
991 				 * Wait a short time for disconnect.
992 				 * Don't be fooled if SII_BER happens first.
993 				 * Note: a reselect may happen here.
994 				 */
995 				SII_WAIT_UNTIL(cstat, regs->cstat,
996 					cstat & (SII_RST | SII_SCH),
997 					SII_WAIT_COUNT, i);
998 				if ((cstat & (SII_RST | SII_SCH |
999 				    SII_STATE_MSK)) == SII_SCH) {
1000 					regs->cstat = SII_SCH | SII_BER;
1001 					regs->comm = 0;
1002 					MachEmptyWriteBuffer();
1003 					/*
1004 					 * Double check that we didn't miss a
1005 					 * state change between seeing it and
1006 					 * clearing the SII_SCH bit.
1007 					 */
1008 					i = regs->cstat;
1009 					if (!(i & SII_SCH) &&
1010 					    (i & SII_STATE_MSK) !=
1011 					    (cstat & SII_STATE_MSK))
1012 						sii_StateChg(sc, i);
1013 				}
1014 #ifdef DEBUG
1015 				if (sii_debug > 4)
1016 					printf("cs %x\n", cstat);
1017 #endif
1018 				sii_CmdDone(sc, msg, 0);
1019 				break;
1020 
1021 			case SCSI_EXTENDED_MSG:
1022 				/* read the message length */
1023 				msg = sii_GetByte(regs, SII_MSG_IN_PHASE);
1024 				if (msg < 0) {
1025 					dstat = regs->dstat;
1026 					goto again;
1027 				}
1028 				if (msg == 0)
1029 					msg = 256;
1030 				sii_StartDMA(regs, SII_MSG_IN_PHASE,
1031 					(u_short *)SII_BUF_ADDR, msg);
1032 				/* wait a short time for XFER complete */
1033 				SII_WAIT_UNTIL(dstat, regs->dstat,
1034 					(dstat & (SII_DNE | SII_TCZ)) ==
1035 					(SII_DNE | SII_TCZ),
1036 					SII_WAIT_COUNT, i);
1037 
1038 				if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) !=
1039 				    (SII_DNE | SII_TCZ)) {
1040 #ifdef DEBUG
1041 					if (sii_debug > 4)
1042 						printf("cnt0 %d\n", i);
1043 					else if (sii_debug > 0)
1044 						printf("sii_DoIntr: emsg in ds %x cnt %d\n",
1045 							dstat, i);
1046 #endif
1047 					printf("sii: ds %x cm %x i %d lotc %d\n",
1048 						dstat, comm, i, regs->dmlotc); /* XXX */
1049 					sii_DumpLog(); /* XXX */
1050 					goto again;
1051 				}
1052 
1053 				/* clear the DNE, other errors handled later */
1054 				regs->dstat = SII_DNE;
1055 				MachEmptyWriteBuffer();
1056 
1057 				CopyFromBuffer((volatile u_short *)SII_BUF_ADDR,
1058 					sii_buf + 2, msg);
1059 				switch (sii_buf[2]) {
1060 				case SCSI_MODIFY_DATA_PTR:
1061 					i = (sii_buf[3] << 24) |
1062 						(sii_buf[4] << 16) |
1063 						(sii_buf[5] << 8) |
1064 						sii_buf[6];
1065 					if (state->dmaPrevPhase >= 0) {
1066 						state->dmaAddrL += i;
1067 						state->dmaCnt -= i;
1068 					}
1069 					break;
1070 
1071 				case SCSI_SYNCHRONOUS_XFER:
1072 					sii_DoSync(regs, state);
1073 					break;
1074 
1075 				case SCSI_EXTENDED_IDENTIFY:
1076 				case SCSI_WIDE_XFER:
1077 				default:
1078 				reject:
1079 					/* send a reject message */
1080 					regs->data = SCSI_MESSAGE_REJECT;
1081 					regs->comm = SII_INXFER | SII_ATN |
1082 						(regs->cstat & SII_STATE_MSK) |
1083 						SII_MSG_OUT_PHASE;
1084 					MachEmptyWriteBuffer();
1085 					/* wait for XFER complete */
1086 					SII_WAIT_UNTIL(dstat, regs->dstat,
1087 						(dstat &
1088 						(SII_DNE | SII_PHASE_MSK)) ==
1089 						(SII_DNE | SII_MSG_OUT_PHASE),
1090 						SII_WAIT_COUNT, i);
1091 
1092 					if ((dstat &
1093 					    (SII_DNE | SII_PHASE_MSK)) !=
1094 					    (SII_DNE | SII_MSG_OUT_PHASE))
1095 						break;
1096 					regs->dstat = SII_DNE;
1097 					MachEmptyWriteBuffer();
1098 				}
1099 				break;
1100 
1101 			case SCSI_SAVE_DATA_POINTER:
1102 			case SCSI_RESTORE_POINTERS:
1103 				/* wait a short time for another msg */
1104 				SII_WAIT_UNTIL(dstat, regs->dstat,
1105 					dstat & (SII_CI | SII_DI),
1106 					SII_WAIT_COUNT, i);
1107 				if (dstat & (SII_CI | SII_DI)) {
1108 #ifdef DEBUG
1109 					if (sii_debug > 4)
1110 						printf("cnt %d\n", i);
1111 #endif
1112 					goto again;
1113 				}
1114 				break;
1115 
1116 			case SCSI_DISCONNECT:
1117 				state->prevComm = comm;
1118 #ifdef DEBUG
1119 				if (sii_debug > 4)
1120 					printf("disconn %d ", sc->sc_target);
1121 #endif
1122 				/*
1123 				 * Wait a short time for disconnect.
1124 				 * Don't be fooled if SII_BER happens first.
1125 				 * Note: a reselect may happen here.
1126 				 */
1127 				SII_WAIT_UNTIL(cstat, regs->cstat,
1128 					cstat & (SII_RST | SII_SCH),
1129 					SII_WAIT_COUNT, i);
1130 				if ((cstat & (SII_RST | SII_SCH |
1131 				    SII_STATE_MSK)) != SII_SCH) {
1132 #ifdef DEBUG
1133 					if (sii_debug > 4)
1134 						printf("cnt %d\n", i);
1135 #endif
1136 					dstat = regs->dstat;
1137 					goto again;
1138 				}
1139 				regs->cstat = SII_SCH | SII_BER;
1140 				regs->comm = 0;
1141 				MachEmptyWriteBuffer();
1142 				sc->sc_target = -1;
1143 				/*
1144 				 * Double check that we didn't miss a state
1145 				 * change between seeing it and clearing
1146 				 * the SII_SCH bit.
1147 				 */
1148 				i = regs->cstat;
1149 				if (!(i & SII_SCH) && (i & SII_STATE_MSK) !=
1150 				    (cstat & SII_STATE_MSK))
1151 					sii_StateChg(sc, i);
1152 				break;
1153 
1154 			case SCSI_MESSAGE_REJECT:
1155 				printf("sii%d: device %d: message reject.\n",
1156 					sc - sii_softc, sc->sc_target);
1157 				goto abort;
1158 
1159 			default:
1160 				if (!(msg & SCSI_IDENTIFY)) {
1161 					printf("sii%d: device %d: couldn't handle message 0x%x... ignoring.\n",
1162 						sc - sii_softc, sc->sc_target,
1163 						msg);
1164 #ifdef DEBUG
1165 					sii_DumpLog();
1166 #endif
1167 					break;
1168 				}
1169 				/* may want to check LUN some day */
1170 				/* wait a short time for another msg */
1171 				SII_WAIT_UNTIL(dstat, regs->dstat,
1172 					dstat & (SII_CI | SII_DI),
1173 					SII_WAIT_COUNT, i);
1174 				if (dstat & (SII_CI | SII_DI)) {
1175 #ifdef DEBUG
1176 					if (sii_debug > 4)
1177 						printf("cnt %d\n", i);
1178 #endif
1179 					goto again;
1180 				}
1181 			}
1182 			break;
1183 
1184 		case SII_MSG_OUT_PHASE:
1185 #ifdef DEBUG
1186 			if (sii_debug > 4)
1187 				printf("MsgOut\n");
1188 #endif
1189 
1190 			regs->data = SCSI_NO_OP;
1191 			regs->comm = SII_INXFER | (comm & SII_STATE_MSK) |
1192 				SII_MSG_OUT_PHASE;
1193 			MachEmptyWriteBuffer();
1194 
1195 			/* wait a short time for XFER complete */
1196 			SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1197 				SII_WAIT_COUNT, i);
1198 #ifdef DEBUG
1199 			if (sii_debug > 4)
1200 				printf("ds %x i %d\n", dstat, i);
1201 #endif
1202 			/* just clear the DNE bit and check errors later */
1203 			if (dstat & SII_DNE) {
1204 				regs->dstat = SII_DNE;
1205 				MachEmptyWriteBuffer();
1206 			}
1207 			break;
1208 
1209 		default:
1210 			printf("sii%d: Couldn't handle phase %d... ignoring.\n",
1211 				   sc - sii_softc, dstat & SII_PHASE_MSK);
1212 		}
1213 	}
1214 
1215 #ifdef DEBUG
1216 	if (sii_debug > 3)
1217 		printf("\n");
1218 #endif
1219 	/*
1220 	 * Check to make sure we won't be interrupted again.
1221 	 * Deglitch dstat register.
1222 	 */
1223 	msg = regs->dstat;
1224 	while (msg != (dstat = regs->dstat))
1225 		msg = dstat;
1226 	if (dstat & (SII_CI | SII_DI))
1227 		goto again;
1228 
1229 	if (sc->sc_target < 0) {
1230 		/* look for another device that is ready */
1231 		for (i = 0; i < SII_NCMD; i++) {
1232 			/* don't restart a disconnected command */
1233 			if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
1234 				continue;
1235 			sii_StartCmd(sc, i);
1236 			break;
1237 		}
1238 	}
1239 	return;
1240 
1241 abort:
1242 	/* jump here to abort the current command */
1243 	printf("sii%d: device %d: current command terminated\n",
1244 		sc - sii_softc, sc->sc_target);
1245 #ifdef DEBUG
1246 	sii_DumpLog();
1247 #endif
1248 
1249 	if ((cstat = regs->cstat) & SII_CON) {
1250 		/* try to send an abort msg for awhile */
1251 		regs->dstat = SII_DNE;
1252 		regs->data = SCSI_ABORT;
1253 		regs->comm = SII_INXFER | SII_ATN | (cstat & SII_STATE_MSK) |
1254 			SII_MSG_OUT_PHASE;
1255 		MachEmptyWriteBuffer();
1256 		SII_WAIT_UNTIL(dstat, regs->dstat,
1257 			(dstat & (SII_DNE | SII_PHASE_MSK)) ==
1258 			(SII_DNE | SII_MSG_OUT_PHASE),
1259 			2 * SII_WAIT_COUNT, i);
1260 #ifdef DEBUG
1261 		if (sii_debug > 0)
1262 			printf("Abort: cs %x ds %x i %d\n", cstat, dstat, i);
1263 #endif
1264 		if (dstat & (SII_DNE | SII_PHASE_MSK) ==
1265 		    (SII_DNE | SII_MSG_OUT_PHASE)) {
1266 			/* disconnect if command in progress */
1267 			regs->comm = SII_DISCON;
1268 			MachEmptyWriteBuffer();
1269 			SII_WAIT_UNTIL(cstat, regs->cstat,
1270 				!(cstat & SII_CON), SII_WAIT_COUNT, i);
1271 		}
1272 	} else {
1273 #ifdef DEBUG
1274 		if (sii_debug > 0)
1275 			printf("Abort: cs %x\n", cstat);
1276 #endif
1277 	}
1278 	regs->cstat = 0xffff;
1279 	regs->dstat = 0xffff;
1280 	regs->comm = 0;
1281 	MachEmptyWriteBuffer();
1282 
1283 	i = sc->sc_target;
1284 	sc->sc_target = -1;
1285 	sii_CmdDone(sc, i, EIO);
1286 #ifdef DEBUG
1287 	if (sii_debug > 4)
1288 		printf("sii_DoIntr: after CmdDone target %d\n", sc->sc_target);
1289 #endif
1290 }
1291 
1292 static void
1293 sii_StateChg(sc, cstat)
1294 	register struct siisoftc *sc;
1295 	register unsigned cstat;
1296 {
1297 	register SIIRegs *regs = sc->sc_regs;
1298 	register State *state;
1299 	register int i;
1300 
1301 #ifdef DEBUG
1302 	if (sii_debug > 4)
1303 		printf("SCH: ");
1304 #endif
1305 
1306 	switch (cstat & SII_STATE_MSK) {
1307 	case 0:
1308 		/* disconnect */
1309 		i = sc->sc_target;
1310 		sc->sc_target = -1;
1311 #ifdef DEBUG
1312 		if (sii_debug > 4)
1313 			printf("disconn %d ", i);
1314 #endif
1315 		if (i >= 0 && !sc->sc_st[i].prevComm) {
1316 			printf("sii%d: device %d: spurrious disconnect (%d)\n",
1317 				sc - sii_softc, i, regs->slcsr);
1318 			sc->sc_st[i].prevComm = 0;
1319 		}
1320 		break;
1321 
1322 	case SII_CON:
1323 		/* connected as initiator */
1324 		i = regs->slcsr;
1325 		if (sc->sc_target == i)
1326 			break;
1327 		printf("sii%d: device %d: connect to device %d??\n",
1328 			sc - sii_softc, sc->sc_target, i);
1329 		sc->sc_target = i;
1330 		break;
1331 
1332 	case SII_DST:
1333 		/*
1334 		 * Wait for CON to become valid,
1335 		 * chip is slow sometimes.
1336 		 */
1337 		SII_WAIT_UNTIL(cstat, regs->cstat,
1338 			cstat & SII_CON, SII_WAIT_COUNT, i);
1339 		if (!(cstat & SII_CON))
1340 			panic("sii resel");
1341 		/* FALLTHROUGH */
1342 
1343 	case SII_CON | SII_DST:
1344 		/*
1345 		 * Its a reselection. Save the ID and wait for
1346 		 * interrupts to tell us what to do next
1347 		 * (should be MSG_IN of IDENTIFY).
1348 		 * NOTE: sc_target may be >= 0 if we were in
1349 		 * the process of trying to start a command
1350 		 * and were reselected before the select
1351 		 * command finished.
1352 		 */
1353 		sc->sc_target = i = regs->destat;
1354 		regs->comm = SII_CON | SII_DST | SII_MSG_IN_PHASE;
1355 		MachEmptyWriteBuffer();
1356 		state = &sc->sc_st[i];
1357 		if (!state->prevComm) {
1358 			printf("sii%d: device %d: spurrious reselection\n",
1359 				sc - sii_softc, i);
1360 			break;
1361 		}
1362 		state->prevComm = 0;
1363 #ifdef DEBUG
1364 		if (sii_debug > 4)
1365 			printf("resel %d ", sc->sc_target);
1366 #endif
1367 		break;
1368 
1369 #ifdef notyet
1370 	case SII_DST | SII_TGT:
1371 	case SII_CON | SII_DST | SII_TGT:
1372 		/* connected as target */
1373 		printf("sii%d: Selected by device %d as target!!\n",
1374 			sc - sii_softc, regs->destat);
1375 		regs->comm = SII_DISCON;
1376 		MachEmptyWriteBuffer();
1377 		SII_WAIT_UNTIL(!(regs->cstat & SII_CON),
1378 			SII_WAIT_COUNT, i);
1379 		regs->cstat = 0xffff;
1380 		regs->dstat = 0xffff;
1381 		regs->comm = 0;
1382 		break;
1383 #endif
1384 
1385 	default:
1386 		printf("sii%d: Unknown state change (cs %x)!!\n",
1387 			sc - sii_softc, cstat);
1388 #ifdef DEBUG
1389 		sii_DumpLog();
1390 #endif
1391 	}
1392 }
1393 
1394 /*
1395  * Read one byte of data.
1396  */
1397 static int
1398 sii_GetByte(regs, phase)
1399 	register SIIRegs *regs;
1400 	int phase;
1401 {
1402 	register unsigned dstat;
1403 	register unsigned state;
1404 #ifdef PROGXFER
1405 	register unsigned data;
1406 
1407 	dstat = regs->dstat;
1408 	state = regs->cstat & SII_STATE_MSK;
1409 	regs->dmctrl = 0;
1410 	if (!(dstat & SII_IBF) || (dstat & SII_MIS)) {
1411 		regs->comm = state | phase;
1412 		MachEmptyWriteBuffer();
1413 		/* wait a short time for IBF */
1414 		SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_IBF,
1415 			SII_WAIT_COUNT, i);
1416 #ifdef DEBUG
1417 		if (!(dstat & SII_IBF))
1418 			printf("status no IBF\n");
1419 #endif
1420 	}
1421 	data = regs->data;
1422 	if (regs->dstat & SII_DNE) { /* XXX */
1423 		printf("sii_GetByte: DNE set 5\n");
1424 		sii_DumpLog();
1425 		regs->dstat = SII_DNE;
1426 	}
1427 	regs->comm = SII_INXFER | state | phase;
1428 	MachEmptyWriteBuffer();
1429 
1430 	/* wait a short time for XFER complete */
1431 	SII_WAIT_UNTIL(dstat, regs->dstat, dstat & SII_DNE,
1432 		SII_WAIT_COUNT, i);
1433 
1434 	if ((dstat & (SII_DNE | SII_IPE)) != SII_DNE) {
1435 #ifdef DEBUG
1436 		if (sii_debug > 4)
1437 			printf("cnt0 %d\n", i);
1438 #endif
1439 		printf("MsgIn %x ?? ds %x cm %x i %d\n",
1440 			data, dstat, comm, i); /* XXX */
1441 		sii_DumpLog(); /* XXX */
1442 		panic("status"); /* XXX */
1443 		goto again;
1444 	}
1445 
1446 	/* clear the DNE, other errors handled later */
1447 	regs->dstat = SII_DNE;
1448 	MachEmptyWriteBuffer();
1449 	return (data);
1450 
1451 #else /* PROGXFER */
1452 	register int i;
1453 
1454 	state = regs->cstat & SII_STATE_MSK;
1455 	regs->dmctrl = 0;
1456 	if (regs->dstat & SII_DNE) {
1457 		printf("sii_GetByte: DNE cs %x ds %x cm %x\n",
1458 			regs->cstat, regs->dstat, regs->comm); /* XXX */
1459 		regs->dstat = SII_DNE;
1460 	}
1461 	regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1);
1462 	regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03;
1463 	regs->dmlotc = 1;
1464 	regs->comm = SII_DMA | SII_INXFER | state | phase;
1465 	MachEmptyWriteBuffer();
1466 
1467 	/* wait a short time for XFER complete */
1468 	SII_WAIT_UNTIL(dstat, regs->dstat,
1469 		(dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ),
1470 		SII_WAIT_COUNT, i);
1471 
1472 	if ((dstat & (SII_DNE | SII_TCZ | SII_IPE)) != (SII_DNE | SII_TCZ)) {
1473 		printf("sii_GetByte: cs %x ds %x cm %x i %d lotc %d\n",
1474 			regs->cstat, dstat, regs->comm, i,
1475 			regs->dmlotc); /* XXX */
1476 		sii_DumpLog(); /* XXX */
1477 		return (-1);
1478 	}
1479 
1480 	/* clear the DNE, other errors handled later */
1481 	regs->dstat = SII_DNE;
1482 	MachEmptyWriteBuffer();
1483 
1484 	/* return one byte of data (optimized CopyFromBuffer()) */
1485 	return (*(volatile u_short *)SII_BUF_ADDR & 0xFF);
1486 #endif /* PROGXFER */
1487 }
1488 
1489 /*
1490  * Exchange messages to initiate synchronous data transfers.
1491  */
1492 static void
1493 sii_DoSync(regs, state)
1494 	register SIIRegs *regs;
1495 	register State *state;
1496 {
1497 	register unsigned dstat;
1498 	register int i;
1499 	unsigned len;
1500 
1501 	printf("sii_DoSync: per %d req/ack %d\n",
1502 		sii_buf[3], sii_buf[4]); /* XXX */
1503 	len = sii_buf[4];
1504 	if (len > 3)
1505 		len = 3;	/* SII chip can only handle 3 max */
1506 
1507 	sii_buf[0] = SCSI_EXTENDED_MSG;
1508 	sii_buf[1] = 3;		/* message length */
1509 	sii_buf[2] = SCSI_SYNCHRONOUS_XFER;
1510 	sii_buf[4] = len;
1511 	CopyToBuffer((u_short *)sii_buf, (volatile u_short *)SII_BUF_ADDR, 5);
1512 	regs->dmaddrl = ((u_short)SII_BUF_ADDR >> 1);
1513 	regs->dmaddrh = ((u_short)SII_BUF_ADDR >> 17) & 03;
1514 	regs->dmlotc = 5;
1515 	regs->comm = SII_DMA | SII_INXFER | SII_ATN |
1516 		(regs->cstat & SII_STATE_MSK) | SII_MSG_OUT_PHASE;
1517 	MachEmptyWriteBuffer();
1518 
1519 	/* wait a short time for XFER complete */
1520 	SII_WAIT_UNTIL(dstat, regs->dstat,
1521 		(dstat & (SII_DNE | SII_TCZ)) == (SII_DNE | SII_TCZ),
1522 		SII_WAIT_COUNT, i);
1523 
1524 	if ((dstat & (SII_DNE | SII_TCZ)) != (SII_DNE | SII_TCZ)) {
1525 		printf("sii_DoSync: ds %x cm %x i %d lotc %d\n",
1526 			dstat, regs->comm, i, regs->dmlotc); /* XXX */
1527 		sii_DumpLog(); /* XXX */
1528 		return;
1529 	}
1530 
1531 	/* clear the DNE, other errors handled later */
1532 	regs->dstat = SII_DNE;
1533 	regs->comm = regs->comm & SII_STATE_MSK;
1534 	MachEmptyWriteBuffer();
1535 
1536 	state->dmaReqAck = len;
1537 }
1538 
1539 /*
1540  * Issue the sequence of commands to the controller to start DMA.
1541  * NOTE: the data buffer should be word-aligned for DMA out.
1542  */
1543 static void
1544 sii_StartDMA(regs, phase, dmaAddr, size)
1545 	register SIIRegs *regs;	/* which SII to use */
1546 	int phase;		/* phase to send/receive data */
1547 	u_short *dmaAddr;	/* DMA buffer address */
1548 	int size;		/* # of bytes to transfer */
1549 {
1550 
1551 	if (regs->dstat & SII_DNE) { /* XXX */
1552 		printf("sii_StartDMA: DNE set\n");
1553 		sii_DumpLog();
1554 		regs->dstat = SII_DNE;
1555 	}
1556 	regs->dmaddrl = ((unsigned)dmaAddr >> 1);
1557 	regs->dmaddrh = ((unsigned)dmaAddr >> 17) & 03;
1558 	regs->dmlotc = size;
1559 	regs->comm = SII_DMA | SII_INXFER | (regs->cstat & SII_STATE_MSK) |
1560 		phase;
1561 	MachEmptyWriteBuffer();
1562 
1563 #ifdef DEBUG
1564 	if (sii_debug > 5) {
1565 		printf("sii_StartDMA: cs 0x%x, ds 0x%x, cm 0x%x, size %d\n",
1566 			regs->cstat, regs->dstat, regs->comm, size);
1567 	}
1568 #endif
1569 }
1570 
1571 /*
1572  * Call the device driver's 'done' routine to let it know the command is done.
1573  * The 'done' routine may try to start another command.
1574  * To be fair, we should start pending commands for other devices
1575  * before allowing the same device to start another command.
1576  */
1577 static void
1578 sii_CmdDone(sc, target, error)
1579 	register struct siisoftc *sc;	/* which SII to use */
1580 	int target;			/* which device is done */
1581 	int error;			/* error code if any errors */
1582 {
1583 	register ScsiCmd *scsicmd;
1584 	register int i;
1585 
1586 	scsicmd = sc->sc_cmd[target];
1587 #ifdef DIAGNOSTIC
1588 	if (target < 0 || !scsicmd)
1589 		panic("sii_CmdDone");
1590 #endif
1591 	sc->sc_cmd[target] = (ScsiCmd *)0;
1592 #ifdef DEBUG
1593 	if (sii_debug > 1) {
1594 		printf("sii_CmdDone: %s target %d cmd %x err %d resid %d\n",
1595 			scsicmd->sd->sd_driver->d_name, target,
1596 			scsicmd->cmd[0], error, sc->sc_st[target].buflen);
1597 	}
1598 #endif
1599 
1600 	/* look for another device that is ready */
1601 	for (i = 0; i < SII_NCMD; i++) {
1602 		/* don't restart a disconnected command */
1603 		if (!sc->sc_cmd[i] || sc->sc_st[i].prevComm)
1604 			continue;
1605 		sii_StartCmd(sc, i);
1606 		break;
1607 	}
1608 
1609 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, error,
1610 		sc->sc_st[target].buflen, sc->sc_st[target].statusByte);
1611 }
1612 
1613 #ifdef DEBUG
1614 sii_DumpLog()
1615 {
1616 	register struct sii_log *lp;
1617 
1618 	printf("sii: cmd %x bn %d cnt %d\n", sii_debug_cmd, sii_debug_bn,
1619 		sii_debug_sz);
1620 	lp = sii_logp;
1621 	do {
1622 		printf("target %d cs %x ds %x cm %x msg %x\n",
1623 			lp->target, lp->cstat, lp->dstat, lp->comm, lp->msg);
1624 		if (++lp >= &sii_log[NLOG])
1625 			lp = sii_log;
1626 	} while (lp != sii_logp);
1627 }
1628 #endif
1629 #endif
1630