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