xref: /netbsd-src/sys/arch/luna68k/stand/boot/sc.c (revision e7caaece8b81daacfba5f3d1c83b7f6f02a8d370)
1 /*	$NetBSD: sc.c,v 1.20 2024/09/25 09:08:22 rin Exp $	*/
2 
3 /*
4  * Copyright (c) 1992 OMRON Corporation.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * OMRON Corporation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)sc.c	8.1 (Berkeley) 6/10/93
38  */
39 /*
40  * Copyright (c) 1992, 1993
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * OMRON Corporation.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  *
70  *	@(#)sc.c	8.1 (Berkeley) 6/10/93
71  */
72 
73 /*
74  * sc.c -- SCSI Protocole Controller (SPC)  driver
75  * remaked by A.Fujita, MAR-11-199
76  */
77 
78 
79 #define NSC	2
80 
81 #include <sys/param.h>
82 #include <luna68k/stand/boot/samachdep.h>
83 #include <luna68k/stand/boot/scsireg.h>
84 #include <luna68k/stand/boot/scsivar.h>
85 
86 #define SCSI_ID		7
87 
88 static void screset(struct scsi_softc *);
89 static void scprobe(struct scsi_softc *, uint, uint);
90 static int issue_select(struct scsidevice *, uint8_t);
91 static void ixfer_start(struct scsidevice *, int, uint8_t, int);
92 static void ixfer_out(struct scsidevice *, int, uint8_t *);
93 static void ixfer_in(struct scsidevice *, int, uint8_t *);
94 static int scrun(int, int, uint8_t *, int, uint8_t *, int, volatile int *);
95 static int scfinish(int);
96 static void scabort(struct scsi_softc *);
97 
98 struct	scsi_softc scsi_softc[NSC];
99 
100 /*
101  * Initialize SPC & Data Structure
102  */
103 
104 int
105 scinit(int ctlr, void *addr)
106 {
107 	struct scsi_softc *hs;
108 	uint id;
109 
110 	if (ctlr < 0 || ctlr >= NSC)
111 		return 0;
112 
113 	hs = &scsi_softc[ctlr];
114 	hs->sc_ctlr   = ctlr;
115 	hs->sc_spc    = addr;
116 
117 	hs->sc_flags  = 0;
118 	hs->sc_phase  = BUS_FREE_PHASE;
119 	hs->sc_target = SCSI_ID;
120 
121 	hs->sc_cdb    = NULL;
122 	hs->sc_cdblen = 0;
123 	hs->sc_buf    = NULL;
124 	hs->sc_len    = 0;
125 	hs->sc_lock   = NULL;
126 
127 	hs->sc_stat   = 0;
128 	hs->sc_msg[0] = 0;
129 
130 	screset(hs);
131 
132 	for (id = 0; id < 7; id++)
133 		scprobe(hs, id, 0);
134 
135 	return 1;
136 }
137 
138 static void
139 screset(struct scsi_softc *hs)
140 {
141 	struct scsidevice *hd = hs->sc_spc;
142 
143 	printf("sc%d at 0x%08lx: ", hs->sc_ctlr, (u_long)hs->sc_spc);
144 
145 	/*
146 	 * Disable interrupts then reset the FUJI chip.
147 	 */
148 
149 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
150 	hd->scsi_scmd = 0;
151 	hd->scsi_pctl = 0;
152 	hd->scsi_temp = 0;
153 	hd->scsi_tch  = 0;
154 	hd->scsi_tcm  = 0;
155 	hd->scsi_tcl  = 0;
156 	hd->scsi_ints = 0;
157 
158 	/* We can use Asynchronous Transfer only */
159 	printf("async");
160 
161 	/*
162 	 * Configure MB89352 with its SCSI address, all
163 	 * interrupts enabled & appropriate parity.
164 	 */
165 	hd->scsi_bdid = SCSI_ID;
166 	hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
167 			SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
168 			SCTL_INTR_ENAB;
169 	printf(", parity");
170 
171 	DELAY(400);
172 	hd->scsi_sctl &= ~SCTL_DISABLE;
173 
174 	printf(", ID %d\n", SCSI_ID);
175 }
176 
177 /*
178  * XXX
179  * sensebuf and inqbuf may be uninitialized for some cases.
180  * Real fix should be to check return values everywhere in
181  * scsi_request_sense(), scsi_immed_command(), and functions
182  * called from them.
183  */
184 #pragma GCC diagnostic push					/* XXX { */
185 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
186 
187 bool
188 scident(uint ctlr, uint target, uint lun, struct scsi_inquiry *inqout,
189     uint32_t *capout)
190 {
191 	struct scsi_inquiry inqbuf;
192 	struct scsi_generic_cdb inq = {
193 		6,
194 		{ CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 }
195 	};
196 	uint32_t capbuf[2];
197 	struct scsi_generic_cdb cap = {
198 		10,
199 		{ CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
200 	};
201 	int i;
202 	int tries = 10;
203 
204 	/*
205 	 * See if unit exists and is a disk then read block size & nblocks.
206 	 */
207 	while ((i = scsi_test_unit_rdy(ctlr, target, lun)) != 0) {
208 		if (i < 0 || --tries < 0)
209 			return false;
210 		if (i == STS_CHECKCOND) {
211 			uint8_t sensebuf[8];
212 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
213 
214 			scsi_request_sense(ctlr, target, lun, sensebuf, 8);
215 			if (sp->class == 7 && sp->key == 6)
216 				/* drive doing an RTZ -- give it a while */
217 				DELAY(1000000);
218 		}
219 		DELAY(1000);
220 	}
221 	if (scsi_immed_command(ctlr, target, lun, &inq, (uint8_t *)&inqbuf,
222 			       sizeof(inqbuf)) ||
223 	    scsi_immed_command(ctlr, target, lun, &cap, (uint8_t *)&capbuf,
224 			       sizeof(capbuf)))
225 		/* doesn't exist or not a CCS device */
226 		return false;
227 
228 	switch (inqbuf.type) {
229 	case 0:		/* disk */
230 	case 4:		/* WORM */
231 	case 5:		/* CD-ROM */
232 	case 7:		/* Magneto-optical */
233 		break;
234 	default:	/* not a disk */
235 		return false;
236 	}
237 
238 	if (inqout != NULL)
239 		*inqout = inqbuf;
240 	if (capout != NULL) {
241 		/* assume big endian */
242 		capout[0] = capbuf[0];
243 		capout[1] = capbuf[1];
244 	}
245 
246 	return true;
247 }
248 
249 #pragma GCC diagnostic pop					/* XXX } */
250 
251 static void
252 scprobe(struct scsi_softc *hs, uint target, uint lun)
253 {
254 	struct scsi_inquiry inqbuf;
255 	uint32_t capbuf[2], blocks, blksize;
256 	char idstr[32];
257 	int i;
258 
259 	if (!scident(hs->sc_ctlr, target, lun, &inqbuf, capbuf))
260 		return;
261 
262 	/* CMD_READ_CAPACITY returns the last logical data block address. */
263 	blocks  = capbuf[0] + 1;
264 	blksize = capbuf[1];
265 
266 	memcpy(idstr, &inqbuf.vendor_id, 28);
267 	for (i = 27; i > 23; --i)
268 		if (idstr[i] != ' ')
269 			break;
270 	idstr[i + 1] = '\0';
271 	for (i = 23; i > 7; --i)
272 		if (idstr[i] != ' ')
273 			break;
274 	idstr[i + 1] = '\0';
275 	for (i = 7; i >= 0; --i)
276 		if (idstr[i] != ' ')
277 			break;
278 	idstr[i + 1] = '\0';
279 
280 	printf(" ID %d: %s %s rev %s", target, idstr, &idstr[8], &idstr[24]);
281 	printf(", %d bytes/sect x %d sectors\n", blksize, blocks);
282 }
283 
284 
285 /*
286  * SPC Arbitration/Selection routine
287  */
288 
289 static int
290 issue_select(struct scsidevice *hd, uint8_t target)
291 {
292 
293 	hd->scsi_pctl = 0;
294 	hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
295 
296 	/* select timeout is hardcoded to 250ms */
297 	hd->scsi_tch = 2;
298 	hd->scsi_tcm = 113;
299 	hd->scsi_tcl = 3;
300 
301 	hd->scsi_scmd = SCMD_SELECT;
302 
303 	return 1;
304 }
305 
306 
307 /*
308  * SPC Manual Transfer routines
309  */
310 
311 /* not yet */
312 
313 
314 /*
315  * SPC Program Transfer routines
316  */
317 
318 static void
319 ixfer_start(struct scsidevice *hd, int len, uint8_t phase, int wait)
320 {
321 
322 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
323 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
324 	hd->scsi_tcl  =  (len & 0x0000ff);
325 	hd->scsi_pctl = phase;
326 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
327 }
328 
329 static void
330 ixfer_out(struct scsidevice *hd, int len, uint8_t *buf)
331 {
332 
333 	for (; len > 0; len--) {
334 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
335 			DELAY(5);
336 		}
337 		hd->scsi_dreg = *buf++;
338 	}
339 }
340 
341 static void
342 ixfer_in(struct scsidevice *hd, int len, uint8_t *buf)
343 {
344 
345 	for (; len > 0; len--) {
346 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
347 			DELAY(5);
348 		}
349 		*buf++ = hd->scsi_dreg;
350 	}
351 }
352 
353 
354 /*
355  * SPC drive routines
356  */
357 
358 static int
359 scrun(int ctlr, int target, uint8_t *cdb, int cdblen, uint8_t *buf, int len,
360     volatile int *lock)
361 {
362 	struct scsi_softc *hs;
363 	struct scsidevice *hd;
364 
365 	if (ctlr < 0 || ctlr >= NSC)
366 		return 0;
367 
368 	hs = &scsi_softc[ctlr];
369 	hd = hs->sc_spc;
370 	if (hd == NULL)
371 		return 0;
372 
373 	if ((hd->scsi_ssts & (SSTS_INITIATOR | SSTS_TARGET | SSTS_BUSY)) != 0)
374 		return 0;
375 
376 	hs->sc_flags  = 0;
377 	hs->sc_phase  = ARB_SEL_PHASE;
378 	hs->sc_target = target;
379 
380 	hs->sc_cdb    = cdb;
381 	hs->sc_cdblen = cdblen;
382 	hs->sc_buf    = buf;
383 	hs->sc_len    = len;
384 	hs->sc_lock   = lock;
385 
386 	hs->sc_stat   = 0;
387 	hs->sc_msg[0] = 0;
388 
389 	*(hs->sc_lock) = SC_IN_PROGRESS;
390 	issue_select(hd, hs->sc_target);
391 
392 	return 1;
393 }
394 
395 static int
396 scfinish(int ctlr)
397 {
398 	struct scsi_softc *hs = &scsi_softc[ctlr];
399 	int status = hs->sc_stat;
400 
401 	hs->sc_flags  = 0;
402 	hs->sc_phase  = BUS_FREE_PHASE;
403 	hs->sc_target = SCSI_ID;
404 
405 	hs->sc_cdb    = NULL;
406 	hs->sc_cdblen = 0;
407 	hs->sc_buf    = NULL;
408 	hs->sc_len    = 0;
409 	hs->sc_lock   = NULL;
410 
411 	hs->sc_stat   = 0;
412 	hs->sc_msg[0] = 0;
413 
414 	return status;
415 }
416 
417 static void
418 scabort(struct scsi_softc *hs)
419 {
420 	struct scsidevice *hd = hs->sc_spc;
421 	int len;
422 
423 	printf("sc%d: abort  phase=0x%x, ssts=0x%x, ints=0x%x\n",
424 	    hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints);
425 
426 	if (hd->scsi_ints != 0)
427 		/* write register value back to register */
428 		hd->scsi_ints = hd->scsi_ints;
429 
430 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
431 		/* no longer connected to scsi target */
432 		return;
433 
434 	/* get the number of bytes remaining in current xfer + fudge */
435 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
436 
437 	/* for that many bus cycles, try to send an abort msg */
438 	for (len += 1024;
439 	    ((hd->scsi_ssts & SSTS_INITIATOR)) != 0 && --len >= 0;) {
440 		hd->scsi_scmd = SCMD_SET_ATN;
441 
442 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
443 			if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
444 				goto out;
445 			DELAY(1);
446 		}
447 
448 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
449 			hd->scsi_scmd = SCMD_RST_ATN;
450 		hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
451 
452 		if (hd->scsi_psns & PHASE_IO) {
453 			/* one of the input phases - read & discard a byte */
454 			hd->scsi_scmd = SCMD_SET_ACK;
455 			while ((hd->scsi_psns & PSNS_REQ) != 0)
456 				DELAY(1);
457 			(void)hd->scsi_temp;
458 		} else {
459 			/* one of the output phases - send an abort msg */
460 			hd->scsi_temp = MSG_ABORT;
461 			hd->scsi_scmd = SCMD_SET_ACK;
462 			while ((hd->scsi_psns & PSNS_REQ) != 0)
463 				DELAY(1);
464 		}
465 
466 		hd->scsi_scmd = SCMD_RST_ACK;
467 	}
468 out:
469 	/*
470 	 * Either the abort was successful & the bus is disconnected or
471 	 * the device didn't listen.  If the latter, announce the problem.
472 	 * Either way, reset the card & the SPC.
473 	 */
474 	if (len < 0 && hs)
475 		printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
476 		    hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts);
477 }
478 
479 
480 /*
481  * SCSI Command Handler
482  */
483 
484 int
485 scsi_test_unit_rdy(int ctlr, int target, int lun)
486 {
487 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
488 	int status;
489 	volatile int lock;
490 
491 #ifdef DEBUG
492 	printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, target, lun);
493 #endif
494 
495 	cdb.lun = lun;
496 
497 	if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) {
498 #ifdef DEBUG
499 		printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
500 #endif
501 		return -1;
502 	}
503 
504 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
505 		DELAY(10);
506 
507 	status = scfinish(ctlr);
508 
509 	if (lock == SC_IO_COMPLETE) {
510 #ifdef DEBUG
511 		printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
512 #endif
513 		return status;
514 	} else {
515 		return lock;
516 	}
517 }
518 
519 int
520 scsi_request_sense(int ctlr, int target, int lun, uint8_t *buf,
521     unsigned int len)
522 {
523 	static struct scsi_cdb6 cdb = {	CMD_REQUEST_SENSE };
524 	int status;
525 	volatile int lock;
526 
527 #ifdef DEBUG
528 	printf("scsi_request_sense: Start\n");
529 #endif
530 
531 	/* Request Senseの場合、転送されるデータ長はターゲットに依存し、        */
532 	/* センスデータの8バイト目のAdditional Sens Lengthにより動的に決定する。*/
533 	/* ここではデーター転送数をcdbのAllocation Lengthに最低長である8バイト */
534 	/* を固定して、SPCの処理シーケンスを崩さないようにしている。         */
535 
536 	/* テープユニットの状態を調べるため、Addtional Sens Fieldをアクセスする */
537 	/* 必要があるのでデバイスドライバ側でlenを決定することにする            */
538 
539 	cdb.lun = lun;
540 	cdb.len = len;
541 
542 	if (scrun(ctlr, target, (void *)&cdb, 6, buf, len, &lock) == 0) {
543 #ifdef DEBUG
544 		printf("scsi_request_sense: Command Transfer Failed.\n");
545 #endif
546 		return -1;
547 	}
548 
549 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
550 		DELAY(10);
551 
552 	status = scfinish(ctlr);
553 
554 	if (lock == SC_IO_COMPLETE) {
555 #ifdef DEBUG
556 		printf("scsi_request_sense: Status -- 0x%x\n", status);
557 #endif
558 		return status;
559 	} else {
560 		return lock;
561 	}
562 }
563 
564 int
565 scsi_immed_command(int ctlr, int target, int lun, struct scsi_generic_cdb *cdb,
566     uint8_t *buf, unsigned int len)
567 {
568 	int status;
569 	volatile int lock;
570 
571 #ifdef DEBUG
572 	printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
573 	    ctlr, target, lun, cdb->len, len);
574 #endif
575 
576 	cdb->cdb[1] |= lun << 5;
577 
578 	if (scrun(ctlr, target, (void *)&cdb->cdb[0], cdb->len, buf, len,
579 	    &lock) == 0) {
580 #ifdef DEBUG
581 		printf("scsi_immed_command: Command Transfer Failed.\n");
582 #endif
583 		return -1;
584 	}
585 
586 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
587 		DELAY(10);
588 
589 	status = scfinish(ctlr);
590 
591 	if (lock == SC_IO_COMPLETE) {
592 #ifdef DEBUG
593 		printf("scsi_immed_command: Status -- 0x%x\n", status);
594 #endif
595 		return status;
596 	} else {
597 		return lock;
598 	}
599 }
600 
601 int
602 scsi_format_unit(int ctlr, int target, int lun)
603 {
604 	static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 };
605 	int status;
606 	volatile int lock;
607 #ifdef DEBUG
608 	int count = 0;
609 #endif
610 
611 #ifdef DEBUG
612 	printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, target, lun);
613 #endif
614 
615 	cdb.lun = lun;
616 
617 	if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) {
618 #ifdef DEBUG
619 		printf("scsi_format_unit: Command Transfer Failed.\n");
620 #endif
621 		return -1;
622 	}
623 
624 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
625 		DELAY(1000000);
626 #ifdef DEBUG
627 		if ((++count % 60) == 0)
628 			printf("scsi_format_unit: %d\n", count / 60);
629 #endif
630 	}
631 
632 	status = scfinish(ctlr);
633 
634 	if (lock == SC_IO_COMPLETE) {
635 #ifdef DEBUG
636 		printf("scsi_format_unit: Status -- 0x%x\n", status);
637 #endif
638 		return status;
639 	} else {
640 		return lock;
641 	}
642 }
643 
644 
645 /*
646  * Interrupt Routine
647  */
648 
649 int
650 scintr(void)
651 {
652 	struct scsi_softc *hs;
653 	struct scsidevice *hd;
654 	uint8_t ints, temp;
655 	int i;
656 	uint8_t *buf;
657 	int len;
658 
659 	for (i = 0; i < NSC; i++) {
660 		hs = &scsi_softc[i];
661 		hd = hs->sc_spc;
662 		if ((ints = hd->scsi_ints) != 0)
663 			goto get_intr;
664 	}
665 
666 	/* Unknown interrupt occurred */
667 	return -1;
668 
669 
670 	/*
671 	 * Interrupt
672 	 */
673 
674  get_intr:
675 #ifdef DEBUG
676 	printf("scintr: INTS 0x%x, SSTS 0x%x,  PCTL 0x%x,  PSNS 0x%x    0x%x\n",
677 	    ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns, hs->sc_phase);
678 #endif
679 	if (ints & INTS_RESEL) {
680 		if (hs->sc_phase == BUS_FREE_PHASE) {
681 			temp = hd->scsi_temp & ~(1 << SCSI_ID);
682 			for (i = 0; temp != 1; i++) {
683 				temp >>= 1;
684 			}
685 			hs->sc_target = i;
686 			*(hs->sc_lock) = SC_IN_PROGRESS;
687 		} else
688 			goto abort;
689 	} else if (ints & INTS_DISCON) {
690 		if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) ||
691 		    (hs->sc_msg[0] == MSG_DISCONNECT)) {
692 			hs->sc_phase  = BUS_FREE_PHASE;
693 			hs->sc_target = SCSI_ID;
694 			if (hs->sc_msg[0] == MSG_CMD_COMPLETE) {
695 				/* SCSI IO complete */
696 				*(hs->sc_lock) = SC_IO_COMPLETE;
697 			} else {
698 				/* Disconnected from Target */
699 				*(hs->sc_lock) = SC_DISCONNECTED;
700 			}
701 			hd->scsi_ints = ints;
702 			return 0;
703 		} else
704 			goto abort;
705 	} else if (ints & INTS_CMD_DONE) {
706 		if (hs->sc_phase == BUS_FREE_PHASE)
707 			goto abort;
708 		else if (hs->sc_phase == MESG_IN_PHASE) {
709 			hd->scsi_scmd = SCMD_RST_ACK;
710 			hd->scsi_ints = ints;
711 			hs->sc_phase  = hd->scsi_psns & PHASE;
712 			return 0;
713 		}
714 		if (hs->sc_flags & SC_SEL_TIMEOUT)
715 			hs->sc_flags &= ~SC_SEL_TIMEOUT;
716 	} else if (ints & INTS_SRV_REQ) {
717 		if (hs->sc_phase != MESG_IN_PHASE)
718 			goto abort;
719 	} else if (ints & INTS_TIMEOUT) {
720 		if (hs->sc_phase == ARB_SEL_PHASE) {
721 			if (hs->sc_flags & SC_SEL_TIMEOUT) {
722 				hs->sc_flags &= ~SC_SEL_TIMEOUT;
723 				hs->sc_phase  = BUS_FREE_PHASE;
724 				hs->sc_target = SCSI_ID;
725 				/* Such SCSI Device is not connected. */
726 				*(hs->sc_lock) = SC_DEV_NOT_FOUND;
727 				hd->scsi_ints = ints;
728 				return 0;
729 			} else {
730 				/* wait more 250 usec */
731 				hs->sc_flags |= SC_SEL_TIMEOUT;
732 				hd->scsi_temp = 0;
733 				hd->scsi_tch  = 0;
734 				hd->scsi_tcm  = 0x06;
735 				hd->scsi_tcl  = 0x40;
736 				hd->scsi_ints = ints;
737 				return 0;
738 			}
739 		} else
740 			goto abort;
741 	} else
742 		goto abort;
743 
744 	hd->scsi_ints = ints;
745 
746 	/*
747 	 * Next SCSI Transfer
748 	 */
749 
750 	while ((hd->scsi_psns & PSNS_REQ) == 0) {
751 		DELAY(1);
752 	}
753 
754 	hs->sc_phase = hd->scsi_psns & PHASE;
755 
756 	if ((hs->sc_phase == DATA_OUT_PHASE) ||
757 	    (hs->sc_phase == DATA_IN_PHASE)) {
758 		len = hs->sc_len;
759 		buf = hs->sc_buf;
760 	} else if (hs->sc_phase == CMD_PHASE) {
761 		len = hs->sc_cdblen;
762 		buf = hs->sc_cdb;
763 	} else if (hs->sc_phase == STATUS_PHASE) {
764 		len = 1;
765 		buf = &hs->sc_stat;
766 	} else {
767 		len = 1;
768 		buf = hs->sc_msg;
769 	}
770 
771 	ixfer_start(hd, len, hs->sc_phase, 0);
772 	if (hs->sc_phase & PHASE_IO)
773 		ixfer_in(hd, len, buf);
774 	else
775 		ixfer_out(hd, len, buf);
776 
777 	return 0;
778 
779 	/*
780 	 * SCSI Abort
781 	 */
782  abort:
783 	/* SCSI IO failed */
784 	scabort(hs);
785 	hd->scsi_ints = ints;
786 	*(hs->sc_lock) = SC_IO_FAILED;
787 	return -1;
788 }
789