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