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