xref: /netbsd-src/sys/arch/amiga/dev/siop.c (revision c41a4eebefede43f6950f838a387dc18c6a431bf)
1 /*	$NetBSD: siop.c,v 1.38 1997/11/27 22:43:44 mhitch Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Michael L. Hitch
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Van Jacobson of Lawrence Berkeley Laboratory.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)siop.c	7.5 (Berkeley) 5/4/91
40  */
41 
42 /*
43  * AMIGA 53C710 scsi adaptor driver
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/disklabel.h>
50 #include <sys/dkstat.h>
51 #include <sys/buf.h>
52 #include <sys/malloc.h>
53 #include <dev/scsipi/scsi_all.h>
54 #include <dev/scsipi/scsipi_all.h>
55 #include <dev/scsipi/scsiconf.h>
56 #include <machine/cpu.h>
57 #include <amiga/amiga/custom.h>
58 #include <amiga/amiga/isr.h>
59 #include <amiga/dev/siopreg.h>
60 #include <amiga/dev/siopvar.h>
61 
62 /*
63  * SCSI delays
64  * In u-seconds, primarily for state changes on the SPC.
65  */
66 #define	SCSI_CMD_WAIT	500000	/* wait per step of 'immediate' cmds */
67 #define	SCSI_DATA_WAIT	500000	/* wait per data in/out step */
68 #define	SCSI_INIT_WAIT	500000	/* wait per step (both) during init */
69 
70 void siop_select __P((struct siop_softc *));
71 void siopabort __P((struct siop_softc *, siop_regmap_p, char *));
72 void sioperror __P((struct siop_softc *, siop_regmap_p, u_char));
73 void siopstart __P((struct siop_softc *));
74 int  siop_checkintr __P((struct siop_softc *, u_char, u_char, u_char, int *));
75 void siopreset __P((struct siop_softc *));
76 void siopsetdelay __P((int));
77 void siop_scsidone __P((struct siop_acb *, int));
78 void siop_sched __P((struct siop_softc *));
79 int  siop_poll __P((struct siop_softc *, struct siop_acb *));
80 void siopintr __P((struct siop_softc *));
81 void scsi_period_to_siop __P((struct siop_softc *, int));
82 void siop_start __P((struct siop_softc *, int, int, u_char *, int, u_char *, int));
83 void siop_dump_acb __P((struct siop_acb *));
84 
85 /* 53C710 script */
86 const
87 #include <amiga/dev/siop_script.out>
88 
89 /* default to not inhibit sync negotiation on any drive */
90 u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
91 u_char siop_allow_disc[8] = {3, 3, 3, 3, 3, 3, 3, 3};
92 int siop_no_dma = 0;
93 
94 int siop_reset_delay = 250;	/* delay after reset, in milleseconds */
95 
96 int siop_cmd_wait = SCSI_CMD_WAIT;
97 int siop_data_wait = SCSI_DATA_WAIT;
98 int siop_init_wait = SCSI_INIT_WAIT;
99 
100 #ifdef DEBUG_SYNC
101 /*
102  * sync period transfer lookup - only valid for 66Mhz clock
103  */
104 static struct {
105 	unsigned char p;	/* period from sync request message */
106 	unsigned char r;	/* siop_period << 4 | sbcl */
107 } sync_tab[] = {
108 	{ 60/4, 0<<4 | 1},
109 	{ 76/4, 1<<4 | 1},
110 	{ 92/4, 2<<4 | 1},
111 	{ 92/4, 0<<4 | 2},
112 	{108/4, 3<<4 | 1},
113 	{116/4, 1<<4 | 2},
114 	{120/4, 4<<4 | 1},
115 	{120/4, 0<<4 | 3},
116 	{136/4, 5<<4 | 1},
117 	{140/4, 2<<4 | 2},
118 	{152/4, 6<<4 | 1},
119 	{152/4, 1<<4 | 3},
120 	{164/4, 3<<4 | 2},
121 	{168/4, 7<<4 | 1},
122 	{180/4, 2<<4 | 3},
123 	{184/4, 4<<4 | 2},
124 	{208/4, 5<<4 | 2},
125 	{212/4, 3<<4 | 3},
126 	{232/4, 6<<4 | 2},
127 	{240/4, 4<<4 | 3},
128 	{256/4, 7<<4 | 2},
129 	{272/4, 5<<4 | 3},
130 	{300/4, 6<<4 | 3},
131 	{332/4, 7<<4 | 3}
132 };
133 #endif
134 
135 #ifdef DEBUG
136 /*
137  *	0x01 - full debug
138  *	0x02 - DMA chaining
139  *	0x04 - siopintr
140  *	0x08 - phase mismatch
141  *	0x10 - <not used>
142  *	0x20 - panic on unhandled exceptions
143  *	0x100 - disconnect/reselect
144  */
145 int	siop_debug = 0;
146 int	siopsync_debug = 0;
147 int	siopdma_hits = 0;
148 int	siopdma_misses = 0;
149 int	siopchain_ints = 0;
150 int	siopstarts = 0;
151 int	siopints = 0;
152 int	siopphmm = 0;
153 #define SIOP_TRACE_SIZE	128
154 #define SIOP_TRACE(a,b,c,d) \
155 	siop_trbuf[siop_trix] = (a); \
156 	siop_trbuf[siop_trix+1] = (b); \
157 	siop_trbuf[siop_trix+2] = (c); \
158 	siop_trbuf[siop_trix+3] = (d); \
159 	siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1);
160 u_char	siop_trbuf[SIOP_TRACE_SIZE];
161 int	siop_trix;
162 void siop_dump __P((struct siop_softc *));
163 void siop_dump_trace __P((void));
164 #else
165 #define SIOP_TRACE(a,b,c,d)
166 #endif
167 
168 
169 /*
170  * default minphys routine for siop based controllers
171  */
172 void
173 siop_minphys(bp)
174 	struct buf *bp;
175 {
176 
177 	/*
178 	 * No max transfer at this level.
179 	 */
180 	minphys(bp);
181 }
182 
183 /*
184  * used by specific siop controller
185  *
186  */
187 int
188 siop_scsicmd(xs)
189 	struct scsipi_xfer *xs;
190 {
191 	struct siop_acb *acb;
192 	struct siop_softc *sc;
193 	struct scsipi_link *slp;
194 	int flags, s;
195 
196 	slp = xs->sc_link;
197 	sc = slp->adapter_softc;
198 	flags = xs->flags;
199 
200 	/* XXXX ?? */
201 	if (flags & SCSI_DATA_UIO)
202 		panic("siop: scsi data uio requested");
203 
204 	/* XXXX ?? */
205 	if (sc->sc_nexus && flags & SCSI_POLL)
206 /*		panic("siop_scsicmd: busy");*/
207 		printf("siop_scsicmd: busy\n");
208 
209 	s = splbio();
210 	acb = sc->free_list.tqh_first;
211 	if (acb) {
212 		TAILQ_REMOVE(&sc->free_list, acb, chain);
213 	}
214 	splx(s);
215 
216 	if (acb == NULL) {
217 		xs->error = XS_DRIVER_STUFFUP;
218 		return(TRY_AGAIN_LATER);
219 	}
220 
221 	acb->flags = ACB_ACTIVE;
222 	acb->xs = xs;
223 	bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
224 	acb->clen = xs->cmdlen;
225 	acb->daddr = xs->data;
226 	acb->dleft = xs->datalen;
227 
228 	s = splbio();
229 	TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
230 
231 	if (sc->sc_nexus == NULL)
232 		siop_sched(sc);
233 
234 	splx(s);
235 
236 	if (flags & SCSI_POLL || siop_no_dma)
237 		return(siop_poll(sc, acb));
238 	return(SUCCESSFULLY_QUEUED);
239 }
240 
241 int
242 siop_poll(sc, acb)
243 	struct siop_softc *sc;
244 	struct siop_acb *acb;
245 {
246 	siop_regmap_p rp = sc->sc_siopp;
247 	struct scsipi_xfer *xs = acb->xs;
248 	int i;
249 	int status;
250 	u_char istat;
251 	u_char dstat;
252 	u_char sstat0;
253 	int s;
254 	int to;
255 
256 	s = splbio();
257 	to = xs->timeout / 1000;
258 	if (sc->nexus_list.tqh_first)
259 		printf("%s: siop_poll called with disconnected device\n",
260 		    sc->sc_dev.dv_xname);
261 	for (;;) {
262 		/* use cmd_wait values? */
263 		i = 50000;
264 		/* XXX spl0(); */
265 		while (((istat = rp->siop_istat) &
266 		    (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
267 			if (--i <= 0) {
268 #ifdef DEBUG
269 				printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %lx (+%lx) dcmd %lx ds %p timeout %d\n",
270 				    xs->sc_link->scsipi_scsi.target, acb->cmd.opcode,
271 				    rp->siop_sbcl, rp->siop_dsp,
272 				    rp->siop_dsp - sc->sc_scriptspa,
273 				    *((long *)&rp->siop_dcmd), &acb->ds, acb->xs->timeout);
274 #endif
275 				i = 50000;
276 				--to;
277 				if (to <= 0) {
278 					siopreset(sc);
279 					return(COMPLETE);
280 				}
281 			}
282 			delay(20);
283 		}
284 		sstat0 = rp->siop_sstat0;
285 		dstat = rp->siop_dstat;
286 		if (siop_checkintr(sc, istat, dstat, sstat0, &status)) {
287 			if (acb != sc->sc_nexus)
288 				printf("%s: siop_poll disconnected device completed\n",
289 				    sc->sc_dev.dv_xname);
290 			else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
291 				sc->sc_flags &= ~SIOP_INTSOFF;
292 				rp->siop_sien = sc->sc_sien;
293 				rp->siop_dien = sc->sc_dien;
294 			}
295 			siop_scsidone(sc->sc_nexus, status);
296 		}
297 		if (xs->flags & ITSDONE)
298 			break;
299 	}
300 	splx(s);
301 	return (COMPLETE);
302 }
303 
304 /*
305  * start next command that's ready
306  */
307 void
308 siop_sched(sc)
309 	struct siop_softc *sc;
310 {
311 	struct scsipi_link *slp;
312 	struct siop_acb *acb;
313 	int i;
314 
315 #ifdef DEBUG
316 	if (sc->sc_nexus) {
317 		printf("%s: siop_sched- nexus %p/%d ready %p/%d\n",
318 		    sc->sc_dev.dv_xname, sc->sc_nexus,
319 		    sc->sc_nexus->xs->sc_link->scsipi_scsi.target,
320 		    sc->ready_list.tqh_first,
321 		    sc->ready_list.tqh_first->xs->sc_link->scsipi_scsi.target);
322 		return;
323 	}
324 #endif
325 	for (acb = sc->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
326 		slp = acb->xs->sc_link;
327 		i = slp->scsipi_scsi.target;
328 		if(!(sc->sc_tinfo[i].lubusy & (1 << slp->scsipi_scsi.lun))) {
329 			struct siop_tinfo *ti = &sc->sc_tinfo[i];
330 
331 			TAILQ_REMOVE(&sc->ready_list, acb, chain);
332 			sc->sc_nexus = acb;
333 			slp = acb->xs->sc_link;
334 			ti = &sc->sc_tinfo[slp->scsipi_scsi.target];
335 			ti->lubusy |= (1 << slp->scsipi_scsi.lun);
336 			break;
337 		}
338 	}
339 
340 	if (acb == NULL) {
341 #ifdef DEBUGXXX
342 		printf("%s: siop_sched didn't find ready command\n",
343 		    sc->sc_dev.dv_xname);
344 #endif
345 		return;
346 	}
347 
348 	if (acb->xs->flags & SCSI_RESET)
349 		siopreset(sc);
350 
351 #if 0
352 	acb->cmd.bytes[0] |= slp->scsipi_scsi.lun << 5;	/* XXXX */
353 #endif
354 	++sc->sc_active;
355 	siop_select(sc);
356 }
357 
358 void
359 siop_scsidone(acb, stat)
360 	struct siop_acb *acb;
361 	int stat;
362 {
363 	struct scsipi_xfer *xs;
364 	struct scsipi_link *slp;
365 	struct siop_softc *sc;
366 	int dosched = 0;
367 
368 	if (acb == NULL || (xs = acb->xs) == NULL) {
369 #ifdef DIAGNOSTIC
370 		printf("siop_scsidone: NULL acb or scsipi_xfer\n");
371 #if defined(DEBUG) && defined(DDB)
372 		Debugger();
373 #endif
374 #endif
375 		return;
376 	}
377 	slp = xs->sc_link;
378 	sc = slp->adapter_softc;
379 	/*
380 	 * is this right?
381 	 */
382 	xs->status = stat;
383 
384 	if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
385 		if (stat == SCSI_CHECK) {
386 			struct scsipi_sense *ss = (void *)&acb->cmd;
387 			bzero(ss, sizeof(*ss));
388 			ss->opcode = REQUEST_SENSE;
389 			ss->byte2 = slp->scsipi_scsi.lun << 5;
390 			ss->length = sizeof(struct scsipi_sense_data);
391 			acb->clen = sizeof(*ss);
392 			acb->daddr = (char *)&xs->sense.scsi_sense;
393 			acb->dleft = sizeof(struct scsipi_sense_data);
394 			acb->flags = ACB_ACTIVE | ACB_CHKSENSE;
395 			TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
396 			--sc->sc_active;
397 			sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &=
398 			    ~(1 << slp->scsipi_scsi.lun);
399 			sc->sc_tinfo[slp->scsipi_scsi.target].senses++;
400 			if (sc->sc_nexus == acb) {
401 				sc->sc_nexus = NULL;
402 				siop_sched(sc);
403 			}
404 			SIOP_TRACE('d','s',0,0)
405 			return;
406 		}
407 	}
408 	if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
409 		xs->error = XS_SENSE;
410 	} else {
411 		xs->resid = 0;		/* XXXX */
412 	}
413 #if whataboutthisone
414 		case SCSI_BUSY:
415 			xs->error = XS_BUSY;
416 			break;
417 #endif
418 	xs->flags |= ITSDONE;
419 
420 	/*
421 	 * Remove the ACB from whatever queue it's on.  We have to do a bit of
422 	 * a hack to figure out which queue it's on.  Note that it is *not*
423 	 * necessary to cdr down the ready queue, but we must cdr down the
424 	 * nexus queue and see if it's there, so we can mark the unit as no
425 	 * longer busy.  This code is sickening, but it works.
426 	 */
427 	if (acb == sc->sc_nexus) {
428 		sc->sc_nexus = NULL;
429 		sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &=
430 			~(1<<slp->scsipi_scsi.lun);
431 		if (sc->ready_list.tqh_first)
432 			dosched = 1;	/* start next command */
433 		--sc->sc_active;
434 		SIOP_TRACE('d','a',stat,0)
435 	} else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
436 		TAILQ_REMOVE(&sc->ready_list, acb, chain);
437 		SIOP_TRACE('d','r',stat,0)
438 	} else {
439 		register struct siop_acb *acb2;
440 		for (acb2 = sc->nexus_list.tqh_first; acb2;
441 		    acb2 = acb2->chain.tqe_next)
442 			if (acb2 == acb) {
443 				TAILQ_REMOVE(&sc->nexus_list, acb, chain);
444 				sc->sc_tinfo[slp->scsipi_scsi.target].lubusy
445 					&= ~(1<<slp->scsipi_scsi.lun);
446 				--sc->sc_active;
447 				break;
448 			}
449 		if (acb2)
450 			;
451 		else if (acb->chain.tqe_next) {
452 			TAILQ_REMOVE(&sc->ready_list, acb, chain);
453 			--sc->sc_active;
454 		} else {
455 			printf("%s: can't find matching acb\n",
456 			    sc->sc_dev.dv_xname);
457 #ifdef DDB
458 /*			Debugger(); */
459 #endif
460 		}
461 		SIOP_TRACE('d','n',stat,0);
462 	}
463 	/* Put it on the free list. */
464 	acb->flags = ACB_FREE;
465 	TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
466 
467 	sc->sc_tinfo[slp->scsipi_scsi.target].cmds++;
468 
469 	scsipi_done(xs);
470 
471 	if (dosched && sc->sc_nexus == NULL)
472 		siop_sched(sc);
473 }
474 
475 void
476 siopabort(sc, rp, where)
477 	register struct siop_softc *sc;
478 	siop_regmap_p rp;
479 	char *where;
480 {
481 #ifdef fix_this
482 	int i;
483 #endif
484 
485 	printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
486 	    sc->sc_dev.dv_xname,
487 	    where, rp->siop_dstat, rp->siop_sstat0, rp->siop_sbcl);
488 
489 	if (sc->sc_active > 0) {
490 #ifdef TODO
491       SET_SBIC_cmd (rp, SBIC_CMD_ABORT);
492       WAIT_CIP (rp);
493 
494       GET_SBIC_asr (rp, asr);
495       if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI))
496         {
497           /* ok, get more drastic.. */
498 
499 	  SET_SBIC_cmd (rp, SBIC_CMD_RESET);
500 	  delay(25);
501 	  SBIC_WAIT(rp, SBIC_ASR_INT, 0);
502 	  GET_SBIC_csr (rp, csr);       /* clears interrupt also */
503 
504           return;
505         }
506 
507       do
508         {
509           SBIC_WAIT (rp, SBIC_ASR_INT, 0);
510           GET_SBIC_csr (rp, csr);
511         }
512       while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
513 	      && (csr != SBIC_CSR_CMD_INVALID));
514 #endif
515 
516 		/* lets just hope it worked.. */
517 #ifdef fix_this
518 		for (i = 0; i < 2; ++i) {
519 			if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] !=
520 			    sc->sc_cur) {
521 				printf ("siopabort: cleanup!\n");
522 				sc->sc_iob[i].sc_xs = NULL;
523 			}
524 		}
525 #endif	/* fix_this */
526 /*		sc->sc_active = 0; */
527 	}
528 }
529 
530 void
531 siopinitialize(sc)
532 	struct siop_softc *sc;
533 {
534 	int i;
535 	u_int inhibit_sync;
536 	extern u_long scsi_nosync;
537 	extern int shift_nosync;
538 
539 	/*
540 	 * Need to check that scripts is on a long word boundary
541 	 * Also should verify that dev doesn't span non-contiguous
542 	 * physical pages.
543 	 */
544 	sc->sc_scriptspa = kvtop((caddr_t)scripts);
545 
546 	/*
547 	 * malloc sc_acb to ensure that DS is on a long word boundary.
548 	 */
549 
550 	MALLOC(sc->sc_acb, struct siop_acb *,
551 		sizeof(struct siop_acb) * SIOP_NACB, M_DEVBUF, M_NOWAIT);
552 	if (sc->sc_acb == NULL)
553 		panic("siopinitialize: ACB malloc failed!");
554 
555 	sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
556 	sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
557 	sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
558 	sc->sc_minsync = sc->sc_tcp[1];		/* in 4ns units */
559 	if (sc->sc_minsync < 25)
560 		sc->sc_minsync = 25;
561 	if (sc->sc_clock_freq <= 25) {
562 		sc->sc_dcntl |= 0x80;		/* SCLK/1 */
563 		sc->sc_tcp[0] = sc->sc_tcp[1];
564 	} else if (sc->sc_clock_freq <= 37) {
565 		sc->sc_dcntl |= 0x40;		/* SCLK/1.5 */
566 		sc->sc_tcp[0] = sc->sc_tcp[2];
567 	} else if (sc->sc_clock_freq <= 50) {
568 		sc->sc_dcntl |= 0x00;		/* SCLK/2 */
569 		sc->sc_tcp[0] = sc->sc_tcp[3];
570 	} else {
571 		sc->sc_dcntl |= 0xc0;		/* SCLK/3 */
572 		sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
573 	}
574 
575 	if (scsi_nosync) {
576 		inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff;
577 		shift_nosync += 8;
578 #ifdef DEBUG
579 		if (inhibit_sync)
580 			printf("%s: Inhibiting synchronous transfer %02x\n",
581 				sc->sc_dev.dv_xname, inhibit_sync);
582 #endif
583 		for (i = 0; i < 8; ++i)
584 			if (inhibit_sync & (1 << i))
585 				siop_inhibit_sync[i] = 1;
586 	}
587 
588 	siopreset (sc);
589 }
590 
591 void
592 siopreset(sc)
593 	struct siop_softc *sc;
594 {
595 	siop_regmap_p rp;
596 	u_int i, s;
597 	u_char  dummy;
598 	struct siop_acb *acb;
599 
600 	rp = sc->sc_siopp;
601 
602 	if (sc->sc_flags & SIOP_ALIVE)
603 		siopabort(sc, rp, "reset");
604 
605 	printf("%s: ", sc->sc_dev.dv_xname);		/* XXXX */
606 
607 	s = splbio();
608 
609 	/*
610 	 * Reset the chip
611 	 * XXX - is this really needed?
612 	 */
613 	rp->siop_istat |= SIOP_ISTAT_ABRT;	/* abort current script */
614 	rp->siop_istat |= SIOP_ISTAT_RST;		/* reset chip */
615 	rp->siop_istat &= ~SIOP_ISTAT_RST;
616 	/*
617 	 * Reset SCSI bus (do we really want this?)
618 	 */
619 	rp->siop_sien = 0;
620 	rp->siop_scntl1 |= SIOP_SCNTL1_RST;
621 	delay(1);
622 	rp->siop_scntl1 &= ~SIOP_SCNTL1_RST;
623 
624 	/*
625 	 * Set up various chip parameters
626 	 */
627 	rp->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG;
628 	rp->siop_scntl1 = SIOP_SCNTL1_ESR;
629 	rp->siop_dcntl = sc->sc_dcntl;
630 	rp->siop_dmode = 0x80;	/* burst length = 4 */
631 	rp->siop_sien = 0x00;	/* don't enable interrupts yet */
632 	rp->siop_dien = 0x00;	/* don't enable interrupts yet */
633 	rp->siop_scid = 1 << sc->sc_link.scsipi_scsi.adapter_target;
634 	rp->siop_dwt = 0x00;
635 	rp->siop_ctest0 |= SIOP_CTEST0_BTD | SIOP_CTEST0_EAN;
636 	rp->siop_ctest7 |= sc->sc_ctest7;
637 
638 	/* will need to re-negotiate sync xfers */
639 	bzero(&sc->sc_sync, sizeof (sc->sc_sync));
640 
641 	i = rp->siop_istat;
642 	if (i & SIOP_ISTAT_SIP)
643 		dummy = rp->siop_sstat0;
644 	if (i & SIOP_ISTAT_DIP)
645 		dummy = rp->siop_dstat;
646 
647 	splx (s);
648 
649 	delay (siop_reset_delay * 1000);
650 	printf("siop id %d reset V%d\n", sc->sc_link.scsipi_scsi.adapter_target,
651 	    rp->siop_ctest8 >> 4);
652 
653 	if ((sc->sc_flags & SIOP_ALIVE) == 0) {
654 		TAILQ_INIT(&sc->ready_list);
655 		TAILQ_INIT(&sc->nexus_list);
656 		TAILQ_INIT(&sc->free_list);
657 		sc->sc_nexus = NULL;
658 		acb = sc->sc_acb;
659 		bzero(acb, sizeof(struct siop_acb) * SIOP_NACB);
660 		for (i = 0; i < SIOP_NACB; i++) {
661 			TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
662 			acb++;
663 		}
664 		bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
665 	} else {
666 		if (sc->sc_nexus != NULL) {
667 			sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
668 			siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
669 		}
670 		while ((acb = sc->nexus_list.tqh_first) > 0) {
671 			acb->xs->error = XS_DRIVER_STUFFUP;
672 			siop_scsidone(acb, acb->stat[0]);
673 		}
674 	}
675 
676 	sc->sc_flags |= SIOP_ALIVE;
677 	sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF);
678 	/* enable SCSI and DMA interrupts */
679 	sc->sc_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE |
680 	    SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR;
681 	sc->sc_dien = SIOP_DIEN_BF | SIOP_DIEN_ABRT | SIOP_DIEN_SIR |
682 	    /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID;
683 	rp->siop_sien = sc->sc_sien;
684 	rp->siop_dien = sc->sc_dien;
685 }
686 
687 /*
688  * Setup Data Storage for 53C710 and start SCRIPTS processing
689  */
690 
691 void
692 siop_start (sc, target, lun, cbuf, clen, buf, len)
693 	struct siop_softc *sc;
694 	int target;
695 	int lun;
696 	u_char *cbuf;
697 	int clen;
698 	u_char *buf;
699 	int len;
700 {
701 	siop_regmap_p rp = sc->sc_siopp;
702 	int nchain;
703 	int count, tcount;
704 	char *addr, *dmaend;
705 	struct siop_acb *acb = sc->sc_nexus;
706 #ifdef DEBUG
707 	int i;
708 #endif
709 
710 #ifdef DEBUG
711 	if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
712 		printf ("ACK! siop was busy: rp %p script %p dsa %p active %ld\n",
713 		    rp, &scripts, &acb->ds, sc->sc_active);
714 		printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
715 		    rp->siop_istat, rp->siop_sfbr, rp->siop_lcrc,
716 		    rp->siop_sien, rp->siop_dien);
717 #ifdef DDB
718 		/*Debugger();*/
719 #endif
720 	}
721 #endif
722 	acb->msgout[0] = MSG_IDENTIFY | lun;
723 	if (siop_allow_disc[target] & 2 ||
724 	    (siop_allow_disc[target] && len == 0))
725 		acb->msgout[0] = MSG_IDENTIFY_DR | lun;
726 	acb->status = 0;
727 	acb->stat[0] = -1;
728 	acb->msg[0] = -1;
729 	acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8);
730 	acb->ds.idlen = 1;
731 	acb->ds.idbuf = (char *) kvtop(&acb->msgout[0]);
732 	acb->ds.cmdlen = clen;
733 	acb->ds.cmdbuf = (char *) kvtop(cbuf);
734 	acb->ds.stslen = 1;
735 	acb->ds.stsbuf = (char *) kvtop(&acb->stat[0]);
736 	acb->ds.msglen = 1;
737 	acb->ds.msgbuf = (char *) kvtop(&acb->msg[0]);
738 	acb->msg[1] = -1;
739 	acb->ds.msginlen = 1;
740 	acb->ds.extmsglen = 1;
741 	acb->ds.synmsglen = 3;
742 	acb->ds.msginbuf = (char *) kvtop(&acb->msg[1]);
743 	acb->ds.extmsgbuf = (char *) kvtop(&acb->msg[2]);
744 	acb->ds.synmsgbuf = (char *) kvtop(&acb->msg[3]);
745 	bzero(&acb->ds.chain, sizeof (acb->ds.chain));
746 
747 	if (sc->sc_sync[target].state == SYNC_START) {
748 		if (siop_inhibit_sync[target]) {
749 			sc->sc_sync[target].state = SYNC_DONE;
750 			sc->sc_sync[target].sbcl = 0;
751 			sc->sc_sync[target].sxfer = 0;
752 #ifdef DEBUG
753 			if (siopsync_debug)
754 				printf ("Forcing target %d asynchronous\n", target);
755 #endif
756 		}
757 		else {
758 			acb->msg[2] = -1;
759 			acb->msgout[1] = MSG_EXT_MESSAGE;
760 			acb->msgout[2] = 3;
761 			acb->msgout[3] = MSG_SYNC_REQ;
762 #ifdef MAXTOR_SYNC_KLUDGE
763 			acb->msgout[4] = 50 / 4;	/* ask for ridiculous period */
764 #else
765 			acb->msgout[4] = sc->sc_minsync;
766 #endif
767 			acb->msgout[5] = SIOP_MAX_OFFSET;
768 			acb->ds.idlen = 6;
769 			sc->sc_sync[target].state = SYNC_SENT;
770 #ifdef DEBUG
771 			if (siopsync_debug)
772 				printf ("Sending sync request to target %d\n", target);
773 #endif
774 		}
775 	}
776 
777 /*
778  * Build physical DMA addresses for scatter/gather I/O
779  */
780 	acb->iob_buf = buf;
781 	acb->iob_len = len;
782 	acb->iob_curbuf = acb->iob_curlen = 0;
783 	nchain = 0;
784 	count = len;
785 	addr = buf;
786 	dmaend = NULL;
787 	while (count > 0) {
788 		acb->ds.chain[nchain].databuf = (char *) kvtop (addr);
789 		if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
790 			tcount = count;
791 		acb->ds.chain[nchain].datalen = tcount;
792 		addr += tcount;
793 		count -= tcount;
794 		if (acb->ds.chain[nchain].databuf == dmaend) {
795 			dmaend += acb->ds.chain[nchain].datalen;
796 			acb->ds.chain[nchain].datalen = 0;
797 			acb->ds.chain[--nchain].datalen += tcount;
798 #ifdef DEBUG
799 			++siopdma_hits;
800 #endif
801 		}
802 		else {
803 			dmaend = acb->ds.chain[nchain].databuf +
804 			    acb->ds.chain[nchain].datalen;
805 			acb->ds.chain[nchain].datalen = tcount;
806 #ifdef DEBUG
807 			if (nchain)	/* Don't count miss on first one */
808 				++siopdma_misses;
809 #endif
810 		}
811 		++nchain;
812 	}
813 #ifdef DEBUG
814 	if (nchain != 1 && len != 0 && siop_debug & 3) {
815 		printf ("DMA chaining set: %d\n", nchain);
816 		for (i = 0; i < nchain; ++i) {
817 			printf ("  [%d] %8p %lx\n", i, acb->ds.chain[i].databuf,
818 			    acb->ds.chain[i].datalen);
819 		}
820 	}
821 #endif
822 
823 	/* push data cache for all data the 53c710 needs to access */
824 	dma_cachectl ((caddr_t)acb, sizeof (struct siop_acb));
825 	dma_cachectl (cbuf, clen);
826 	if (buf != NULL && len != 0)
827 		dma_cachectl (buf, len);
828 #ifdef DEBUG
829 	if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
830 		printf ("ACK! siop was busy at start: rp %p script %p dsa %p active %ld\n",
831 		    rp, &scripts, &acb->ds, sc->sc_active);
832 #ifdef DDB
833 		/*Debugger();*/
834 #endif
835 	}
836 #endif
837 	if (sc->nexus_list.tqh_first == NULL) {
838 		if (rp->siop_istat & SIOP_ISTAT_CON)
839 			printf("%s: siop_select while connected?\n",
840 			    sc->sc_dev.dv_xname);
841 		rp->siop_temp = 0;
842 		rp->siop_sbcl = sc->sc_sync[target].sbcl;
843 		rp->siop_dsa = kvtop((caddr_t)&acb->ds);
844 		rp->siop_dsp = sc->sc_scriptspa;
845 		SIOP_TRACE('s',1,0,0)
846 	} else {
847 		if ((rp->siop_istat & SIOP_ISTAT_CON) == 0) {
848 			rp->siop_istat = SIOP_ISTAT_SIGP;
849 			SIOP_TRACE('s',2,0,0);
850 		}
851 		else {
852 			SIOP_TRACE('s',3,rp->siop_istat,0);
853 		}
854 	}
855 #ifdef DEBUG
856 	++siopstarts;
857 #endif
858 }
859 
860 /*
861  * Process a DMA or SCSI interrupt from the 53C710 SIOP
862  */
863 
864 int
865 siop_checkintr(sc, istat, dstat, sstat0, status)
866 	struct	siop_softc *sc;
867 	u_char	istat;
868 	u_char	dstat;
869 	u_char	sstat0;
870 	int	*status;
871 {
872 	siop_regmap_p rp = sc->sc_siopp;
873 	struct siop_acb *acb = sc->sc_nexus;
874 	int	target = 0;
875 	int	dfifo, dbc, sstat1;
876 
877 	dfifo = rp->siop_dfifo;
878 	dbc = rp->siop_dbc0;
879 	sstat1 = rp->siop_sstat1;
880 	rp->siop_ctest8 |= SIOP_CTEST8_CLF;
881 	while ((rp->siop_ctest1 & SIOP_CTEST1_FMT) != SIOP_CTEST1_FMT)
882 		;
883 	rp->siop_ctest8 &= ~SIOP_CTEST8_CLF;
884 #ifdef DEBUG
885 	++siopints;
886 #if 0
887 	if (siop_debug & 0x100) {
888 		DCIAS(&acb->stat[0]);	/* XXX */
889 		printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
890 		    istat, dstat, sstat0, rp->siop_dsps, rp->siop_sbcl, acb->stat[0], acb->msg[0]);
891 		printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
892 		    acb->msg[0], acb->msg[1], acb->msg[2],
893 		    acb->msg[3], acb->msg[4], acb->msg[5]);
894 	}
895 #endif
896 	if (rp->siop_dsp && (rp->siop_dsp < sc->sc_scriptspa ||
897 	    rp->siop_dsp >= sc->sc_scriptspa + sizeof(scripts))) {
898 		printf ("%s: dsp not within script dsp %lx scripts %lx:%lx",
899 		    sc->sc_dev.dv_xname, rp->siop_dsp, sc->sc_scriptspa,
900 		    sc->sc_scriptspa + sizeof(scripts));
901 		printf(" istat %x dstat %x sstat0 %x\n",
902 		    istat, dstat, sstat0);
903 #ifdef DDB
904 		Debugger();
905 #endif
906 	}
907 #endif
908 	SIOP_TRACE('i',dstat,istat,(istat&SIOP_ISTAT_DIP)?rp->siop_dsps&0xff:sstat0);
909 	if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff00) {
910 		/* Normal completion status, or check condition */
911 #ifdef DEBUG
912 		if (rp->siop_dsa != kvtop((caddr_t)&acb->ds)) {
913 			printf ("siop: invalid dsa: %lx %x\n", rp->siop_dsa,
914 			    kvtop((caddr_t)&acb->ds));
915 			panic("*** siop DSA invalid ***");
916 		}
917 #endif
918 		target = acb->xs->sc_link->scsipi_scsi.target;
919 		if (sc->sc_sync[target].state == SYNC_SENT) {
920 #ifdef DEBUG
921 			if (siopsync_debug)
922 				printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
923 				    acb->msg[0], acb->msg[1], acb->msg[2],
924 				    acb->msg[3], acb->msg[4], acb->msg[5]);
925 #endif
926 			if (acb->msg[1] == 0xff)
927 				printf ("%s: target %d ignored sync request\n",
928 				    sc->sc_dev.dv_xname, target);
929 			else if (acb->msg[1] == MSG_REJECT)
930 				printf ("%s: target %d rejected sync request\n",
931 				    sc->sc_dev.dv_xname, target);
932 			sc->sc_sync[target].state = SYNC_DONE;
933 			sc->sc_sync[target].sxfer = 0;
934 			sc->sc_sync[target].sbcl = 0;
935 			if (acb->msg[2] == 3 &&
936 			    acb->msg[3] == MSG_SYNC_REQ &&
937 			    acb->msg[5] != 0) {
938 #ifdef MAXTOR_KLUDGE
939 				/*
940 				 * Kludge for my Maxtor XT8580S
941 				 * It accepts whatever we request, even
942 				 * though it won't work.  So we ask for
943 				 * a short period than we can handle.  If
944 				 * the device says it can do it, use 208ns.
945 				 * If the device says it can do less than
946 				 * 100ns, then we limit it to 100ns.
947 				 */
948 				if (acb->msg[4] && acb->msg[4] < 100 / 4) {
949 #ifdef DEBUG
950 					printf ("%d: target %d wanted %dns period\n",
951 					    sc->sc_dev.dv_xname, target,
952 					    acb->msg[4] * 4);
953 #endif
954 					if (acb->msg[4] == 50 / 4)
955 						acb->msg[4] = 208 / 4;
956 					else
957 						acb->msg[4] = 100 / 4;
958 				}
959 #endif /* MAXTOR_KLUDGE */
960 				printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
961 				    sc->sc_dev.dv_xname, target,
962 				    acb->msg[4] * 4, acb->msg[5]);
963 				scsi_period_to_siop (sc, target);
964 			}
965 		}
966 		dma_cachectl(&acb->stat[0], 1);
967 		*status = acb->stat[0];
968 #ifdef DEBUG
969 		if (rp->siop_sbcl & SIOP_BSY) {
970 			/*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n",
971 			    rp, &scripts, &acb->ds);*/
972 #ifdef DDB
973 			/*Debugger();*/
974 #endif
975 		}
976 		if (acb->msg[0] != 0x00)
977 			printf("%s: message was not COMMAND COMPLETE: %x\n",
978 			    sc->sc_dev.dv_xname, acb->msg[0]);
979 #endif
980 		if (sc->nexus_list.tqh_first)
981 			rp->siop_dcntl |= SIOP_DCNTL_STD;
982 		return 1;
983 	}
984 	if (sstat0 & SIOP_SSTAT0_M_A) {		/* Phase mismatch */
985 #ifdef DEBUG
986 		++siopphmm;
987 		if (acb == NULL)
988 			printf("%s: Phase mismatch with no active command?\n",
989 			    sc->sc_dev.dv_xname);
990 #endif
991 		if (acb->iob_len) {
992 			int adjust;
993 			adjust = ((dfifo - (dbc & 0x7f)) & 0x7f);
994 			if (sstat1 & SIOP_SSTAT1_ORF)
995 				++adjust;
996 			if (sstat1 & SIOP_SSTAT1_OLF)
997 				++adjust;
998 			acb->iob_curlen = *((long *)&rp->siop_dcmd) & 0xffffff;
999 			acb->iob_curlen += adjust;
1000 			acb->iob_curbuf = *((long *)&rp->siop_dnad) - adjust;
1001 #ifdef DEBUG
1002 			if (siop_debug & 0x100) {
1003 				int i;
1004 				printf ("Phase mismatch: curbuf %lx curlen %lx dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %p\n",
1005 				    acb->iob_curbuf, acb->iob_curlen, dfifo,
1006 				    dbc, sstat1, adjust, rp->siop_sbcl, siopstarts, acb);
1007 				if (acb->ds.chain[1].datalen) {
1008 					for (i = 0; acb->ds.chain[i].datalen; ++i)
1009 						printf("chain[%d] addr %p len %lx\n",
1010 						    i, acb->ds.chain[i].databuf,
1011 						    acb->ds.chain[i].datalen);
1012 				}
1013 			}
1014 #endif
1015 			dma_cachectl ((caddr_t)acb, sizeof(*acb));
1016 		}
1017 #ifdef DEBUG
1018 		SIOP_TRACE('m',rp->siop_sbcl,(rp->siop_dsp>>8),rp->siop_dsp);
1019 		if (siop_debug & 9)
1020 			printf ("Phase mismatch: %x dsp +%lx dcmd %lx\n",
1021 			    rp->siop_sbcl,
1022 			    rp->siop_dsp - sc->sc_scriptspa,
1023 			    *((long *)&rp->siop_dcmd));
1024 #endif
1025 		if ((rp->siop_sbcl & SIOP_REQ) == 0) {
1026 			printf ("Phase mismatch: REQ not asserted! %02x dsp %lx\n",
1027 			    rp->siop_sbcl, rp->siop_dsp);
1028 #if defined(DEBUG) && defined(DDB)
1029 			Debugger();
1030 #endif
1031 		}
1032 		switch (rp->siop_sbcl & 7) {
1033 		case 0:		/* data out */
1034 		case 1:		/* data in */
1035 		case 2:		/* status */
1036 		case 3:		/* command */
1037 		case 6:		/* message in */
1038 		case 7:		/* message out */
1039 			rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
1040 			break;
1041 		default:
1042 			goto bad_phase;
1043 		}
1044 		return 0;
1045 	}
1046 	if (sstat0 & SIOP_SSTAT0_STO) {		/* Select timed out */
1047 #ifdef DEBUG
1048 		if (acb == NULL)
1049 			printf("%s: Select timeout with no active command?\n",
1050 			    sc->sc_dev.dv_xname);
1051 		if (rp->siop_sbcl & SIOP_BSY) {
1052 			printf ("ACK! siop was busy at timeout: rp %p script %p dsa %p\n",
1053 			    rp, &scripts, &acb->ds);
1054 			printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
1055 			    rp->siop_sbcl, rp->siop_sdid, istat, dstat, sstat0);
1056 			if (!(rp->siop_sbcl & SIOP_BSY)) {
1057 				printf ("Yikes, it's not busy now!\n");
1058 #if 0
1059 				*status = -1;
1060 				if (sc->nexus_list.tqh_first)
1061 					rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1062 				return 1;
1063 #endif
1064 			}
1065 /*			rp->siop_dcntl |= SIOP_DCNTL_STD;*/
1066 			return (0);
1067 #ifdef DDB
1068 			Debugger();
1069 #endif
1070 		}
1071 #endif
1072 		*status = -1;
1073 		acb->xs->error = XS_SELTIMEOUT;
1074 		if (sc->nexus_list.tqh_first)
1075 			rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1076 		return 1;
1077 	}
1078 	if (acb)
1079 		target = acb->xs->sc_link->scsipi_scsi.target;
1080 	else
1081 		target = 7;
1082 	if (sstat0 & SIOP_SSTAT0_UDC) {
1083 #ifdef DEBUG
1084 		if (acb == NULL)
1085 			printf("%s: Unexpected disconnect with no active command?\n",
1086 			    sc->sc_dev.dv_xname);
1087 		printf ("%s: target %d disconnected unexpectedly\n",
1088 		   sc->sc_dev.dv_xname, target);
1089 #endif
1090 #if 0
1091 		siopabort (sc, rp, "siopchkintr");
1092 #endif
1093 		*status = STS_BUSY;
1094 		if (sc->nexus_list.tqh_first)
1095 			rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1096 		return (acb != NULL);
1097 	}
1098 	if (dstat & SIOP_DSTAT_SIR && (rp->siop_dsps == 0xff01 ||
1099 	    rp->siop_dsps == 0xff02)) {
1100 #ifdef DEBUG
1101 		if (siop_debug & 0x100)
1102 			printf ("%s: ID %02x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n",
1103 			    sc->sc_dev.dv_xname, 1 << target, rp->siop_temp,
1104 			    rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0,
1105 			    acb->iob_curbuf, acb->iob_curlen,
1106 			    acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb);
1107 #endif
1108 		if (acb == NULL) {
1109 			printf("%s: Disconnect with no active command?\n",
1110 			    sc->sc_dev.dv_xname);
1111 			return (0);
1112 		}
1113 		/*
1114 		 * XXXX need to update iob_curbuf/iob_curlen to reflect
1115 		 * current data transferred.  If device disconnected in
1116 		 * the middle of a DMA block, they should already be set
1117 		 * by the phase change interrupt.  If the disconnect
1118 		 * occurs on a DMA block boundary, we have to figure out
1119 		 * which DMA block it was.
1120 		 */
1121 		if (acb->iob_len && rp->siop_temp) {
1122 			int n = rp->siop_temp - sc->sc_scriptspa;
1123 
1124 			if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen)
1125 				printf("%s: iob_curbuf/len already set? n %x iob %lx/%lx chain[0] %p/%lx\n",
1126 				    sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen,
1127 				    acb->ds.chain[0].databuf, acb->ds.chain[0].datalen);
1128 			if (n < Ent_datain)
1129 				n = (n - Ent_dataout) / 16;
1130 			else
1131 				n = (n - Ent_datain) / 16;
1132 			if (n <= 0 && n > DMAMAXIO)
1133 				printf("TEMP invalid %d\n", n);
1134 			else {
1135 				acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf;
1136 				acb->iob_curlen = acb->ds.chain[n].datalen;
1137 			}
1138 #ifdef DEBUG
1139 			if (siop_debug & 0x100) {
1140 				printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n);
1141 				printf(" curbuf %lx curlen %lx\n", acb->iob_curbuf,
1142 				    acb->iob_curlen);
1143 			}
1144 #endif
1145 		}
1146 		/*
1147 		 * If data transfer was interrupted by disconnect, iob_curbuf
1148 		 * and iob_curlen should reflect the point of interruption.
1149 		 * Adjust the DMA chain so that the data transfer begins
1150 		 * at the appropriate place upon reselection.
1151 		 * XXX This should only be done on save data pointer message?
1152 		 */
1153 		if (acb->iob_curlen) {
1154 			int i, j;
1155 
1156 #ifdef DEBUG
1157 			if (siop_debug & 0x100)
1158 				printf ("%s: adjusting DMA chain\n",
1159 				    sc->sc_dev.dv_xname);
1160 			if (rp->siop_dsps == 0xff02)
1161 				printf ("%s: ID %02x disconnected without Save Data Pointers\n",
1162 				    sc->sc_dev.dv_xname, 1 << target);
1163 #endif
1164 			for (i = 0; i < DMAMAXIO; ++i) {
1165 				if (acb->ds.chain[i].datalen == 0)
1166 					break;
1167 				if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf &&
1168 				    acb->iob_curbuf < (long)(acb->ds.chain[i].databuf +
1169 				    acb->ds.chain[i].datalen))
1170 					break;
1171 			}
1172 			if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0) {
1173 				printf("couldn't find saved data pointer: ");
1174 				printf("curbuf %lx curlen %lx i %d\n",
1175 				    acb->iob_curbuf, acb->iob_curlen, i);
1176 #ifdef DDB
1177 				Debugger();
1178 #endif
1179 			}
1180 #ifdef DEBUG
1181 			if (siop_debug & 0x100)
1182 				printf("  chain[0]: %p/%lx -> %lx/%lx\n",
1183 				    acb->ds.chain[0].databuf,
1184 				    acb->ds.chain[0].datalen,
1185 				    acb->iob_curbuf,
1186 				    acb->iob_curlen);
1187 #endif
1188 			acb->ds.chain[0].databuf = (char *)acb->iob_curbuf;
1189 			acb->ds.chain[0].datalen = acb->iob_curlen;
1190 			for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) {
1191 #ifdef DEBUG
1192 			if (siop_debug & 0x100)
1193 				printf("  chain[%d]: %p/%lx -> %p/%lx\n", j,
1194 				    acb->ds.chain[j].databuf,
1195 				    acb->ds.chain[j].datalen,
1196 				    acb->ds.chain[i].databuf,
1197 				    acb->ds.chain[i].datalen);
1198 #endif
1199 				acb->ds.chain[j].databuf = acb->ds.chain[i].databuf;
1200 				acb->ds.chain[j].datalen = acb->ds.chain[i].datalen;
1201 			}
1202 			if (j < DMAMAXIO)
1203 				acb->ds.chain[j].datalen = 0;
1204 			DCIAS(kvtop((caddr_t)&acb->ds.chain));
1205 		}
1206 		++sc->sc_tinfo[target].dconns;
1207 		/*
1208 		 * add nexus to waiting list
1209 		 * clear nexus
1210 		 * try to start another command for another target/lun
1211 		 */
1212 		acb->status = sc->sc_flags & SIOP_INTSOFF;
1213 		TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
1214 		sc->sc_nexus = NULL;		/* no current device */
1215 		/* start script to wait for reselect */
1216 		if (sc->sc_nexus == NULL)
1217 			rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1218 /* XXXX start another command ? */
1219 		if (sc->ready_list.tqh_first)
1220 			siop_sched(sc);
1221 		return (0);
1222 	}
1223 	if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff03) {
1224 		int reselid = rp->siop_scratch & 0x7f;
1225 		int reselun = rp->siop_sfbr & 0x07;
1226 
1227 		sc->sc_sstat1 = rp->siop_sbcl;	/* XXXX save current SBCL */
1228 #ifdef DEBUG
1229 		if (siop_debug & 0x100)
1230 			printf ("%s: target ID %02x reselected dsps %lx\n",
1231 			     sc->sc_dev.dv_xname, reselid,
1232 			     rp->siop_dsps);
1233 		if ((rp->siop_sfbr & 0x80) == 0)
1234 			printf("%s: Reselect message in was not identify: %x\n",
1235 			    sc->sc_dev.dv_xname, rp->siop_sfbr);
1236 #endif
1237 		if (sc->sc_nexus) {
1238 #ifdef DEBUG
1239 			if (siop_debug & 0x100)
1240 				printf ("%s: reselect ID %02x w/active\n",
1241 				    sc->sc_dev.dv_xname, reselid);
1242 #endif
1243 			TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
1244 			sc->sc_tinfo[sc->sc_nexus->xs->sc_link->scsipi_scsi.target].lubusy
1245 			    &= ~(1 << sc->sc_nexus->xs->sc_link->scsipi_scsi.lun);
1246 			--sc->sc_active;
1247 		}
1248 		/*
1249 		 * locate acb of reselecting device
1250 		 * set sc->sc_nexus to acb
1251 		 */
1252 		for (acb = sc->nexus_list.tqh_first; acb;
1253 		    acb = acb->chain.tqe_next) {
1254 			if (reselid != (acb->ds.scsi_addr >> 16) ||
1255 			    reselun != (acb->msgout[0] & 0x07))
1256 				continue;
1257 			TAILQ_REMOVE(&sc->nexus_list, acb, chain);
1258 			sc->sc_nexus = acb;
1259 			sc->sc_flags |= acb->status;
1260 			acb->status = 0;
1261 			DCIAS(kvtop(&acb->stat[0]));
1262 			rp->siop_dsa = kvtop((caddr_t)&acb->ds);
1263 			rp->siop_sxfer =
1264 				sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sxfer;
1265 			rp->siop_sbcl =
1266 				sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sbcl;
1267 			break;
1268 		}
1269 		if (acb == NULL) {
1270 			printf("%s: target ID %02x reselect nexus_list %p\n",
1271 			    sc->sc_dev.dv_xname, reselid,
1272 			    sc->nexus_list.tqh_first);
1273 			panic("unable to find reselecting device");
1274 		}
1275 		dma_cachectl ((caddr_t)acb, sizeof(*acb));
1276 		rp->siop_temp = 0;
1277 		rp->siop_dcntl |= SIOP_DCNTL_STD;
1278 		return (0);
1279 	}
1280 	if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff04) {
1281 #ifdef DEBUG
1282 		u_short ctest2 = rp->siop_ctest2;
1283 
1284 		/* reselect was interrupted (by Sig_P or select) */
1285 		if (siop_debug & 0x100 ||
1286 		    (ctest2 & SIOP_CTEST2_SIGP) == 0)
1287 			printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
1288 			    sc->sc_dev.dv_xname, rp->siop_scntl1,
1289 			    ctest2, rp->siop_sfbr, istat, rp->siop_istat);
1290 #endif
1291 		/* XXX assumes it was not select */
1292 		if (sc->sc_nexus == NULL) {
1293 #ifdef DEBUG
1294 			printf("%s: reselect interrupted, sc_nexus == NULL\n",
1295 			    sc->sc_dev.dv_xname);
1296 #if 0
1297 			siop_dump(sc);
1298 #ifdef DDB
1299 			Debugger();
1300 #endif
1301 #endif
1302 #endif
1303 			rp->siop_dcntl |= SIOP_DCNTL_STD;
1304 			return(0);
1305 		}
1306 		target = sc->sc_nexus->xs->sc_link->scsipi_scsi.target;
1307 		rp->siop_temp = 0;
1308 		rp->siop_dsa = kvtop((caddr_t)&sc->sc_nexus->ds);
1309 		rp->siop_sxfer = sc->sc_sync[target].sxfer;
1310 		rp->siop_sbcl = sc->sc_sync[target].sbcl;
1311 		rp->siop_dsp = sc->sc_scriptspa;
1312 		return (0);
1313 	}
1314 	if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff06) {
1315 		if (acb == NULL)
1316 			printf("%s: Bad message-in with no active command?\n",
1317 			    sc->sc_dev.dv_xname);
1318 		/* Unrecognized message in byte */
1319 		dma_cachectl (&acb->msg[1],1);
1320 		printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
1321 			sc->sc_dev.dv_xname, rp->siop_sfbr, acb->msg[1], rp->siop_sbcl);
1322 		/* what should be done here? */
1323 		DCIAS(kvtop(&acb->msg[1]));
1324 		rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
1325 		return (0);
1326 	}
1327 	if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0a) {
1328 		/* Status phase wasn't followed by message in phase? */
1329 		printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
1330 			sc->sc_dev.dv_xname, rp->siop_sbcl, rp->siop_sbdl);
1331 		if (rp->siop_sbcl == 0xa7) {
1332 			/* It is now, just continue the script? */
1333 			rp->siop_dcntl |= SIOP_DCNTL_STD;
1334 			return (0);
1335 		}
1336 	}
1337 	if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) {
1338 		dma_cachectl (&acb->stat[0], 1);
1339 		dma_cachectl (&acb->msg[0], 1);
1340 		printf ("SIOP interrupt: %lx sts %x msg %x %x sbcl %x\n",
1341 		    rp->siop_dsps, acb->stat[0], acb->msg[0], acb->msg[1],
1342 		    rp->siop_sbcl);
1343 		siopreset (sc);
1344 		*status = -1;
1345 		return 0;	/* siopreset has cleaned up */
1346 	}
1347 	if (sstat0 & SIOP_SSTAT0_SGE)
1348 		printf ("SIOP: SCSI Gross Error\n");
1349 	if (sstat0 & SIOP_SSTAT0_PAR)
1350 		printf ("SIOP: Parity Error\n");
1351 	if (dstat & SIOP_DSTAT_IID)
1352 		printf ("SIOP: Invalid instruction detected\n");
1353 bad_phase:
1354 	/*
1355 	 * temporary panic for unhandled conditions
1356 	 * displays various things about the 53C710 status and registers
1357 	 * then panics.
1358 	 * XXXX need to clean this up to print out the info, reset, and continue
1359 	 */
1360 	printf ("siopchkintr: target %x ds %p\n", target, &acb->ds);
1361 	printf ("scripts %lx ds %x rp %x dsp %lx dcmd %lx\n", sc->sc_scriptspa,
1362 	    kvtop((caddr_t)&acb->ds), kvtop((caddr_t)rp), rp->siop_dsp,
1363 	    *((long *)&rp->siop_dcmd));
1364 	printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %lx dsa %lx sbcl %x sts %x msg %x %x sfbr %x\n",
1365 	    istat, dstat, sstat0, rp->siop_dsps, rp->siop_dsa,
1366 	     rp->siop_sbcl, acb->stat[0], acb->msg[0], acb->msg[1], rp->siop_sfbr);
1367 #ifdef DEBUG
1368 	if (siop_debug & 0x20)
1369 		panic("siopchkintr: **** temp ****");
1370 #endif
1371 #ifdef DDB
1372 	Debugger ();
1373 #endif
1374 	siopreset (sc);		/* hard reset */
1375 	*status = -1;
1376 	return 0;		/* siopreset cleaned up */
1377 }
1378 
1379 void
1380 siop_select(sc)
1381 	struct siop_softc *sc;
1382 {
1383 	siop_regmap_p rp;
1384 	struct siop_acb *acb = sc->sc_nexus;
1385 
1386 #ifdef DEBUG
1387 	if (siop_debug & 1)
1388 		printf ("%s: select ", sc->sc_dev.dv_xname);
1389 #endif
1390 
1391 	rp = sc->sc_siopp;
1392 	if (acb->xs->flags & SCSI_POLL || siop_no_dma) {
1393 		sc->sc_flags |= SIOP_INTSOFF;
1394 		sc->sc_flags &= ~SIOP_INTDEFER;
1395 		if ((rp->siop_istat & 0x08) == 0) {
1396 			rp->siop_sien = 0;
1397 			rp->siop_dien = 0;
1398 		}
1399 #if 0
1400 	} else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
1401 		sc->sc_flags &= ~SIOP_INTSOFF;
1402 		if ((rp->siop_istat & 0x08) == 0) {
1403 			rp->siop_sien = sc->sc_sien;
1404 			rp->siop_dien = sc->sc_dien;
1405 		}
1406 #endif
1407 	}
1408 #ifdef DEBUG
1409 	if (siop_debug & 1)
1410 		printf ("siop_select: target %x cmd %02x ds %p\n",
1411 		    acb->xs->sc_link->scsipi_scsi.target, acb->cmd.opcode,
1412 		    &sc->sc_nexus->ds);
1413 #endif
1414 
1415 	siop_start(sc, acb->xs->sc_link->scsipi_scsi.target,
1416 		acb->xs->sc_link->scsipi_scsi.lun,
1417 	    (u_char *)&acb->cmd, acb->clen, acb->daddr, acb->dleft);
1418 
1419 	return;
1420 }
1421 
1422 /*
1423  * 53C710 interrupt handler
1424  */
1425 
1426 void
1427 siopintr (sc)
1428 	register struct siop_softc *sc;
1429 {
1430 	siop_regmap_p rp;
1431 	register u_char istat, dstat, sstat0;
1432 	int status;
1433 	int s = splbio();
1434 
1435 	istat = sc->sc_istat;
1436 	if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
1437 		splx(s);
1438 		return;
1439 	}
1440 
1441 	/* Got a valid interrupt on this device */
1442 	rp = sc->sc_siopp;
1443 	dstat = sc->sc_dstat;
1444 	sstat0 = sc->sc_sstat0;
1445 	if (dstat & SIOP_DSTAT_SIR)
1446 		sc->sc_intcode = rp->siop_dsps;
1447 	sc->sc_istat = 0;
1448 #ifdef DEBUG
1449 	if (siop_debug & 1)
1450 		printf ("%s: intr istat %x dstat %x sstat0 %x\n",
1451 		    sc->sc_dev.dv_xname, istat, dstat, sstat0);
1452 	if (!sc->sc_active) {
1453 		printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x nexus %p status %x\n",
1454 		    sc->sc_dev.dv_xname, istat, dstat, sstat0,
1455 		    sc->sc_nexus, sc->sc_nexus ? sc->sc_nexus->stat[0] : 0);
1456 	}
1457 #endif
1458 
1459 #ifdef DEBUG
1460 	if (siop_debug & 5) {
1461 		DCIAS(kvtop(&sc->sc_nexus->stat[0]));
1462 		printf ("%s: intr istat %x dstat %x sstat0 %x dsps %lx sbcl %x sts %x msg %x\n",
1463 		    sc->sc_dev.dv_xname, istat, dstat, sstat0,
1464 		    rp->siop_dsps,  rp->siop_sbcl,
1465 		    sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]);
1466 	}
1467 #endif
1468 	if (sc->sc_flags & SIOP_INTDEFER) {
1469 		sc->sc_flags &= ~(SIOP_INTDEFER | SIOP_INTSOFF);
1470 		rp->siop_sien = sc->sc_sien;
1471 		rp->siop_dien = sc->sc_dien;
1472 	}
1473 	if (siop_checkintr (sc, istat, dstat, sstat0, &status)) {
1474 #if 1
1475 		if (status == 0xff)
1476 			printf ("siopintr: status == 0xff\n");
1477 #endif
1478 		if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) {
1479 #if 0
1480 			if (rp->siop_sbcl & SIOP_BSY) {
1481 				printf ("%s: SCSI bus busy at completion",
1482 					sc->sc_dev.dv_xname);
1483 				printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
1484 				    sc->sc_nexus->xs->sc_link->scsipi_scsi.target,
1485 				    rp->siop_sbcl, rp->siop_sfbr, rp->siop_lcrc,
1486 				    rp->siop_dsp - sc->sc_scriptspa);
1487 			}
1488 #endif
1489 			siop_scsidone(sc->sc_nexus, sc->sc_nexus ?
1490 			    sc->sc_nexus->stat[0] : -1);
1491 		}
1492 	}
1493 	splx(s);
1494 }
1495 
1496 /*
1497  * This is based on the Progressive Peripherals 33Mhz Zeus driver and will
1498  * not be correct for other 53c710 boards.
1499  *
1500  */
1501 void
1502 scsi_period_to_siop (sc, target)
1503 	struct siop_softc *sc;
1504 	int target;
1505 {
1506 	int period, offset, sxfer, sbcl = 0;
1507 #ifdef DEBUG_SYNC
1508 	int i;
1509 #endif
1510 
1511 	period = sc->sc_nexus->msg[4];
1512 	offset = sc->sc_nexus->msg[5];
1513 #ifdef DEBUG_SYNC
1514 	sxfer = 0;
1515 	if (offset <= SIOP_MAX_OFFSET)
1516 		sxfer = offset;
1517 	for (i = 0; i < sizeof (sync_tab) / 2; ++i) {
1518 		if (period <= sync_tab[i].p) {
1519 			sxfer |= sync_tab[i].r & 0x70;
1520 			sbcl = sync_tab[i].r & 0x03;
1521 			break;
1522 		}
1523 	}
1524 	printf ("siop sync old: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
1525 #endif
1526 	for (sbcl = 1; sbcl < 4; ++sbcl) {
1527 		sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
1528 		if (sxfer >= 0 && sxfer <= 7)
1529 			break;
1530 	}
1531 	if (sbcl > 3) {
1532 		printf("siop sync: unable to compute sync params for period %dns\n",
1533 		    period * 4);
1534 		/*
1535 		 * XXX need to pick a value we can do and renegotiate
1536 		 */
1537 		sxfer = sbcl = 0;
1538 	} else {
1539 		sxfer = (sxfer << 4) | ((offset <= SIOP_MAX_OFFSET) ?
1540 		    offset : SIOP_MAX_OFFSET);
1541 #ifdef DEBUG_SYNC
1542 		printf("siop sync: params for period %dns: sxfer %x sbcl %x",
1543 		    period * 4, sxfer, sbcl);
1544 		printf(" actual period %dns\n",
1545 		    sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4));
1546 #endif
1547 	}
1548 	sc->sc_sync[target].sxfer = sxfer;
1549 	sc->sc_sync[target].sbcl = sbcl;
1550 #ifdef DEBUG_SYNC
1551 	printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
1552 #endif
1553 }
1554 
1555 #ifdef DEBUG
1556 
1557 #if SIOP_TRACE_SIZE
1558 void
1559 siop_dump_trace()
1560 {
1561 	int i;
1562 
1563 	printf("siop trace: next index %d\n", siop_trix);
1564 	i = siop_trix;
1565 	do {
1566 		printf("%3d: '%c' %02x %02x %02x\n", i, siop_trbuf[i],
1567 		    siop_trbuf[i + 1], siop_trbuf[i + 2], siop_trbuf[i + 3]);
1568 		i = (i + 4) & (SIOP_TRACE_SIZE - 1);
1569 	} while (i != siop_trix);
1570 }
1571 #endif
1572 
1573 void
1574 siop_dump_acb(acb)
1575 	struct siop_acb *acb;
1576 {
1577 	u_char *b = (u_char *) &acb->cmd;
1578 	int i;
1579 
1580 	printf("acb@%p ", acb);
1581 	if (acb->xs == NULL) {
1582 		printf("<unused>\n");
1583 		return;
1584 	}
1585 	printf("(%d:%d) flags %2x clen %2d cmd ",
1586 		acb->xs->sc_link->scsipi_scsi.target,
1587 	    acb->xs->sc_link->scsipi_scsi.lun, acb->flags, acb->clen);
1588 	for (i = acb->clen; i; --i)
1589 		printf(" %02x", *b++);
1590 	printf("\n");
1591 	printf("  xs: %p data %p:%04x ", acb->xs, acb->xs->data,
1592 	    acb->xs->datalen);
1593 	printf("va %p:%lx ", acb->iob_buf, acb->iob_len);
1594 	printf("cur %lx:%lx\n", acb->iob_curbuf, acb->iob_curlen);
1595 }
1596 
1597 void
1598 siop_dump(sc)
1599 	struct siop_softc *sc;
1600 {
1601 	struct siop_acb *acb;
1602 	siop_regmap_p rp = sc->sc_siopp;
1603 	int s;
1604 	int i;
1605 
1606 	s = splbio();
1607 #if SIOP_TRACE_SIZE
1608 	siop_dump_trace();
1609 #endif
1610 	printf("%s@%p regs %p istat %x\n",
1611 	    sc->sc_dev.dv_xname, sc, rp, rp->siop_istat);
1612 	if ((acb = sc->free_list.tqh_first) > 0) {
1613 		printf("Free list:\n");
1614 		while (acb) {
1615 			siop_dump_acb(acb);
1616 			acb = acb->chain.tqe_next;
1617 		}
1618 	}
1619 	if ((acb = sc->ready_list.tqh_first) > 0) {
1620 		printf("Ready list:\n");
1621 		while (acb) {
1622 			siop_dump_acb(acb);
1623 			acb = acb->chain.tqe_next;
1624 		}
1625 	}
1626 	if ((acb = sc->nexus_list.tqh_first) > 0) {
1627 		printf("Nexus list:\n");
1628 		while (acb) {
1629 			siop_dump_acb(acb);
1630 			acb = acb->chain.tqe_next;
1631 		}
1632 	}
1633 	if (sc->sc_nexus) {
1634 		printf("Nexus:\n");
1635 		siop_dump_acb(sc->sc_nexus);
1636 	}
1637 	for (i = 0; i < 8; ++i) {
1638 		if (sc->sc_tinfo[i].cmds > 2) {
1639 			printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n",
1640 			    i, sc->sc_tinfo[i].cmds,
1641 			    sc->sc_tinfo[i].dconns,
1642 			    sc->sc_tinfo[i].senses,
1643 			    sc->sc_tinfo[i].lubusy);
1644 		}
1645 	}
1646 	splx(s);
1647 }
1648 #endif
1649