Home | History | Annotate | Line # | Download | only in boot
sc.c revision 1.11
      1 /*	$NetBSD: sc.c,v 1.11 2014/04/16 11:18:00 tsutsui 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 *, u_char);
     91 static void ixfer_start(struct scsidevice *, int, u_char, int);
     92 static void ixfer_out(struct scsidevice *, int, u_char *);
     93 static void ixfer_in(struct scsidevice *, int, u_char *);
     94 static int scrun(int, int, u_char *, int, u_char *, 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 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 bool
    178 scident(uint ctlr, uint target, uint lun, struct scsi_inquiry *inqout,
    179     uint32_t *capout)
    180 {
    181 	struct scsi_inquiry inqbuf;
    182 	struct scsi_generic_cdb inq = {
    183 		6,
    184 		{ CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 }
    185 	};
    186 	uint32_t capbuf[2];
    187 	struct scsi_generic_cdb cap = {
    188 		10,
    189 		{ CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    190 	};
    191 	int i;
    192 	int tries = 10;
    193 
    194 	/*
    195 	 * See if unit exists and is a disk then read block size & nblocks.
    196 	 */
    197 	while ((i = scsi_test_unit_rdy(ctlr, target, lun)) != 0) {
    198 		if (i < 0 || --tries < 0)
    199 			return false;
    200 		if (i == STS_CHECKCOND) {
    201 			u_char sensebuf[8];
    202 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
    203 
    204 			scsi_request_sense(ctlr, target, lun, sensebuf, 8);
    205 			if (sp->class == 7 && sp->key == 6)
    206 				/* drive doing an RTZ -- give it a while */
    207 				DELAY(1000000);
    208 		}
    209 		DELAY(1000);
    210 	}
    211 	if (scsi_immed_command(ctlr, target, lun, &inq, (u_char *)&inqbuf,
    212 			       sizeof(inqbuf)) ||
    213 	    scsi_immed_command(ctlr, target, lun, &cap, (u_char *)&capbuf,
    214 			       sizeof(capbuf)))
    215 		/* doesn't exist or not a CCS device */
    216 		return false;
    217 
    218 	switch (inqbuf.type) {
    219 	case 0:		/* disk */
    220 	case 4:		/* WORM */
    221 	case 5:		/* CD-ROM */
    222 	case 7:		/* Magneto-optical */
    223 		break;
    224 	default:	/* not a disk */
    225 		return false;
    226 	}
    227 
    228 	if (inqout != NULL)
    229 		*inqout = inqbuf;
    230 	if (capout != NULL) {
    231 		/* assume big endian */
    232 		capout[0] = capbuf[0];
    233 		capout[1] = capbuf[1];
    234 	}
    235 
    236 	return true;
    237 }
    238 
    239 static void
    240 scprobe(struct scsi_softc *hs, uint target, uint lun)
    241 {
    242 	struct scsi_inquiry inqbuf;
    243 	uint32_t capbuf[2];
    244 	char idstr[32];
    245 	int i;
    246 
    247 	if (!scident(hs->sc_ctlr, target, lun, &inqbuf, capbuf))
    248 		return;
    249 
    250 	memcpy(idstr, &inqbuf.vendor_id, 28);
    251 	for (i = 27; i > 23; --i)
    252 		if (idstr[i] != ' ')
    253 			break;
    254 	idstr[i + 1] = '\0';
    255 	for (i = 23; i > 7; --i)
    256 		if (idstr[i] != ' ')
    257 			break;
    258 	idstr[i + 1] = '\0';
    259 	for (i = 7; i >= 0; --i)
    260 		if (idstr[i] != ' ')
    261 			break;
    262 	idstr[i + 1] = '\0';
    263 
    264 	printf(" ID %d: %s %s rev %s", target, idstr, &idstr[8], &idstr[24]);
    265 	printf(", %d bytes/sect x %d sectors\n", capbuf[1], capbuf[0]);
    266 }
    267 
    268 
    269 /*
    270  * SPC Arbitration/Selection routine
    271  */
    272 
    273 int
    274 issue_select(struct scsidevice *hd, u_char target)
    275 {
    276 
    277 	hd->scsi_pctl = 0;
    278 	hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
    279 
    280 	/* select timeout is hardcoded to 250ms */
    281 	hd->scsi_tch = 2;
    282 	hd->scsi_tcm = 113;
    283 	hd->scsi_tcl = 3;
    284 
    285 	hd->scsi_scmd = SCMD_SELECT;
    286 
    287 	return 1;
    288 }
    289 
    290 
    291 /*
    292  * SPC Manual Transfer routines
    293  */
    294 
    295 /* not yet */
    296 
    297 
    298 /*
    299  * SPC Program Transfer routines
    300  */
    301 
    302 void
    303 ixfer_start(struct scsidevice *hd, int len, u_char phase, int wait)
    304 {
    305 
    306 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
    307 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
    308 	hd->scsi_tcl  =  (len & 0x0000ff);
    309 	hd->scsi_pctl = phase;
    310 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
    311 }
    312 
    313 void
    314 ixfer_out(struct scsidevice *hd, int len, u_char *buf)
    315 {
    316 
    317 	for (; len > 0; len--) {
    318 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
    319 			DELAY(5);
    320 		}
    321 		hd->scsi_dreg = *buf++;
    322 	}
    323 }
    324 
    325 void
    326 ixfer_in(struct scsidevice *hd, int len, u_char *buf)
    327 {
    328 
    329 	for (; len > 0; len--) {
    330 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
    331 			DELAY(5);
    332 		}
    333 		*buf++ = hd->scsi_dreg;
    334 	}
    335 }
    336 
    337 
    338 /*
    339  * SPC drive routines
    340  */
    341 
    342 int
    343 scrun(int ctlr, int target, u_char *cdb, int cdblen, u_char *buf, int len,
    344     volatile int *lock)
    345 {
    346 	struct scsi_softc *hs;
    347 	struct scsidevice *hd;
    348 
    349 	if (ctlr < 0 || ctlr >= NSC)
    350 		return 0;
    351 
    352 	hs = &scsi_softc[ctlr];
    353 	hd = hs->sc_spc;
    354 	if (hd == NULL)
    355 		return 0;
    356 
    357 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
    358 		return 0;
    359 
    360 	hs->sc_flags  = 0;
    361 	hs->sc_phase  = ARB_SEL_PHASE;
    362 	hs->sc_target = target;
    363 
    364 	hs->sc_cdb    = cdb;
    365 	hs->sc_cdblen = cdblen;
    366 	hs->sc_buf    = buf;
    367 	hs->sc_len    = len;
    368 	hs->sc_lock   = lock;
    369 
    370 	hs->sc_stat   = 0;
    371 	hs->sc_msg[0] = 0;
    372 
    373 	*(hs->sc_lock) = SC_IN_PROGRESS;
    374 	issue_select(hd, hs->sc_target);
    375 
    376 	return 1;
    377 }
    378 
    379 int
    380 scfinish(int ctlr)
    381 {
    382 	struct scsi_softc *hs = &scsi_softc[ctlr];
    383 	int status = hs->sc_stat;
    384 
    385 	hs->sc_flags  = 0;
    386 	hs->sc_phase  = BUS_FREE_PHASE;
    387 	hs->sc_target = SCSI_ID;
    388 
    389 	hs->sc_cdb    = NULL;
    390 	hs->sc_cdblen = 0;
    391 	hs->sc_buf    = NULL;
    392 	hs->sc_len    = 0;
    393 	hs->sc_lock   = NULL;
    394 
    395 	hs->sc_stat   = 0;
    396 	hs->sc_msg[0] = 0;
    397 
    398 	return status;
    399 }
    400 
    401 void
    402 scabort(struct scsi_softc *hs)
    403 {
    404 	struct scsidevice *hd = hs->sc_spc;
    405 	int len;
    406 
    407 	printf("sc%d: abort  phase=0x%x, ssts=0x%x, ints=0x%x\n",
    408 		hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts,
    409 		hd->scsi_ints);
    410 
    411 	if (hd->scsi_ints != 0)
    412 		hd->scsi_ints = hd->scsi_ints;
    413 
    414 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
    415 		/* no longer connected to scsi target */
    416 		return;
    417 
    418 	/* get the number of bytes remaining in current xfer + fudge */
    419 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
    420 
    421 	/* for that many bus cycles, try to send an abort msg */
    422 	for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
    423 		hd->scsi_scmd = SCMD_SET_ATN;
    424 
    425 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
    426 			if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
    427 				goto out;
    428 			DELAY(1);
    429 		}
    430 
    431 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
    432 			hd->scsi_scmd = SCMD_RST_ATN;
    433 		hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
    434 
    435 		if (hd->scsi_psns & PHASE_IO) {
    436 			/* one of the input phases - read & discard a byte */
    437 			hd->scsi_scmd = SCMD_SET_ACK;
    438 			while (hd->scsi_psns & PSNS_REQ)
    439 				DELAY(1);
    440 			(void)hd->scsi_temp;
    441 		} else {
    442 			/* one of the output phases - send an abort msg */
    443 			hd->scsi_temp = MSG_ABORT;
    444 			hd->scsi_scmd = SCMD_SET_ACK;
    445 			while (hd->scsi_psns & PSNS_REQ)
    446 				DELAY(1);
    447 		}
    448 
    449 		hd->scsi_scmd = SCMD_RST_ACK;
    450 	}
    451 out:
    452 	/*
    453 	 * Either the abort was successful & the bus is disconnected or
    454 	 * the device didn't listen.  If the latter, announce the problem.
    455 	 * Either way, reset the card & the SPC.
    456 	 */
    457 	if (len < 0 && hs)
    458 		printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
    459 			hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts);
    460 }
    461 
    462 
    463 /*
    464  * SCSI Command Handler
    465  */
    466 
    467 int
    468 scsi_test_unit_rdy(int ctlr, int target, int lun)
    469 {
    470 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
    471 	int status;
    472 	volatile int lock;
    473 
    474 #ifdef DEBUG
    475 	printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, target, lun);
    476 #endif
    477 
    478 	cdb.lun = lun;
    479 
    480 	if (!(scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock))) {
    481 #ifdef DEBUG
    482 		printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
    483 #endif
    484 		return -1;
    485 	}
    486 
    487 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
    488 		DELAY(10);
    489 
    490 	status = scfinish(ctlr);
    491 
    492 	if (lock == SC_IO_COMPLETE) {
    493 #ifdef DEBUG
    494 		printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
    495 #endif
    496 		return status;
    497 	} else {
    498 		return lock;
    499 	}
    500 }
    501 
    502 int
    503 scsi_request_sense(int ctlr, int target, int lun, u_char *buf, unsigned int len)
    504 {
    505 	static struct scsi_cdb6 cdb = {	CMD_REQUEST_SENSE };
    506 	int status;
    507 	volatile int lock;
    508 
    509 #ifdef DEBUG
    510 	printf("scsi_request_sense: Start\n");
    511 #endif
    512 
    513 	/* Request Sense        */
    514 	/* Additional Sens Length*/
    515 	/* cdbAllocation Length */
    516 	/*          */
    517 
    518 	/* Addtional Sens Field */
    519 	/* len            */
    520 
    521 	cdb.lun = lun;
    522 	cdb.len = len;
    523 
    524 	if (!(scrun(ctlr, target, (void *)&cdb, 6, buf, len, &lock))) {
    525 #ifdef DEBUG
    526 		printf("scsi_request_sense: Command Transfer Failed.\n");
    527 #endif
    528 		return -1;
    529 	}
    530 
    531 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
    532 		DELAY(10);
    533 
    534 	status = scfinish(ctlr);
    535 
    536 	if (lock == SC_IO_COMPLETE) {
    537 #ifdef DEBUG
    538 		printf("scsi_request_sense: Status -- 0x%x\n", status);
    539 #endif
    540 		return status;
    541 	} else {
    542 		return lock;
    543 	}
    544 }
    545 
    546 int
    547 scsi_immed_command(int ctlr, int target, int lun, struct scsi_generic_cdb *cdb,
    548     u_char *buf, unsigned int len)
    549 {
    550 	int status;
    551 	volatile int lock;
    552 
    553 #ifdef DEBUG
    554 	printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
    555 	       ctlr, target, lun, cdb->len, len);
    556 #endif
    557 
    558 	cdb->cdb[1] |= lun << 5;
    559 
    560 	if (!(scrun(ctlr, target, (void *)&cdb->cdb[0], cdb->len, buf, len,
    561 	    &lock))) {
    562 #ifdef DEBUG
    563 		printf("scsi_immed_command: Command Transfer Failed.\n");
    564 #endif
    565 		return -1;
    566 	}
    567 
    568 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
    569 		DELAY(10);
    570 
    571 	status = scfinish(ctlr);
    572 
    573 	if (lock == SC_IO_COMPLETE) {
    574 #ifdef DEBUG
    575 		printf("scsi_immed_command: Status -- 0x%x\n", status);
    576 #endif
    577 		return status;
    578 	} else {
    579 		return lock;
    580 	}
    581 }
    582 
    583 int
    584 scsi_format_unit(int ctlr, int target, int lun)
    585 {
    586 	static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 };
    587 	int status;
    588 	volatile int lock;
    589 #ifdef DEBUG
    590 	int count = 0;
    591 #endif
    592 
    593 #ifdef DEBUG
    594 	printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, target, lun);
    595 #endif
    596 
    597 	cdb.lun = lun;
    598 
    599 	if (!(scrun(ctlr, target, (void *)&cdb, 6, (u_char *) 0, 0, &lock))) {
    600 #ifdef DEBUG
    601 		printf("scsi_format_unit: Command Transfer Failed.\n");
    602 #endif
    603 		return -1;
    604 	}
    605 
    606 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
    607 		DELAY(1000000);
    608 #ifdef DEBUG
    609 		if ((++count % 60) == 0)
    610 			printf("scsi_format_unit: %d\n", count / 60);
    611 #endif
    612 	}
    613 
    614 	status = scfinish(ctlr);
    615 
    616 	if (lock == SC_IO_COMPLETE) {
    617 #ifdef DEBUG
    618 		printf("scsi_format_unit: Status -- 0x%x\n", status);
    619 #endif
    620 		return status;
    621 	} else {
    622 		return lock;
    623 	}
    624 }
    625 
    626 
    627 /*
    628  * Interrupt Routine
    629  */
    630 
    631 int
    632 scintr(void)
    633 {
    634 	struct scsi_softc *hs;
    635 	struct scsidevice *hd;
    636 	u_char ints, temp;
    637 	int i;
    638 	u_char *buf;
    639 	int len;
    640 
    641 	for (i = 0; i < NSC; i++) {
    642 		hs = &scsi_softc[i];
    643 		hd = hs->sc_spc;
    644 		if ((ints = hd->scsi_ints) != 0)
    645 			goto get_intr;
    646 	}
    647 
    648 	/* Unknown Interrupt occured */
    649 	return -1;
    650 
    651 
    652 	/*
    653 	 * Interrupt
    654 	 */
    655 
    656  get_intr:
    657 #ifdef DEBUG
    658 	printf("scintr: INTS 0x%x, SSTS 0x%x,  PCTL 0x%x,  PSNS 0x%x    0x%x\n",
    659 	        ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns,
    660 	        hs->sc_phase);
    661 #endif
    662 	if (ints & INTS_RESEL) {
    663 		if (hs->sc_phase == BUS_FREE_PHASE) {
    664 			temp = hd->scsi_temp & ~(1 << SCSI_ID);
    665 			for (i = 0; temp != 1; i++) {
    666 				temp >>= 1;
    667 			}
    668 			hs->sc_target = i;
    669 			*(hs->sc_lock) = SC_IN_PROGRESS;
    670 		} else
    671 			goto abort;
    672 	} else if (ints & INTS_DISCON) {
    673 		if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) ||
    674 		    (hs->sc_msg[0] == MSG_DISCONNECT)) {
    675 			hs->sc_phase  = BUS_FREE_PHASE;
    676 			hs->sc_target = SCSI_ID;
    677 			if (hs->sc_msg[0] == MSG_CMD_COMPLETE)
    678 				/* SCSI IO complete */
    679 				*(hs->sc_lock) = SC_IO_COMPLETE;
    680 			else
    681 				/* Cisconnected from Target */
    682 				*(hs->sc_lock) = SC_DISCONNECTED;
    683 			hd->scsi_ints = ints;
    684 			return 0;
    685 		} else
    686 			goto abort;
    687 	} else if (ints & INTS_CMD_DONE) {
    688 		if (hs->sc_phase == BUS_FREE_PHASE)
    689 			goto abort;
    690 		else if (hs->sc_phase == MESG_IN_PHASE) {
    691 			hd->scsi_scmd = SCMD_RST_ACK;
    692 			hd->scsi_ints = ints;
    693 			hs->sc_phase  = hd->scsi_psns & PHASE;
    694 			return 0;
    695 		}
    696 		if (hs->sc_flags & SC_SEL_TIMEOUT)
    697 			hs->sc_flags &= ~SC_SEL_TIMEOUT;
    698 	} else if (ints & INTS_SRV_REQ) {
    699 		if (hs->sc_phase != MESG_IN_PHASE)
    700 			goto abort;
    701 	} else if (ints & INTS_TIMEOUT) {
    702 		if (hs->sc_phase == ARB_SEL_PHASE) {
    703 			if (hs->sc_flags & SC_SEL_TIMEOUT) {
    704 				hs->sc_flags &= ~SC_SEL_TIMEOUT;
    705 				hs->sc_phase  = BUS_FREE_PHASE;
    706 				hs->sc_target = SCSI_ID;
    707 				/* Such SCSI Device is not conected. */
    708 				*(hs->sc_lock) = SC_DEV_NOT_FOUND;
    709 				hd->scsi_ints = ints;
    710 				return 0;
    711 			} else {
    712 				/* wait more 250 usec */
    713 				hs->sc_flags |= SC_SEL_TIMEOUT;
    714 				hd->scsi_temp = 0;
    715 				hd->scsi_tch  = 0;
    716 				hd->scsi_tcm  = 0x06;
    717 				hd->scsi_tcl  = 0x40;
    718 				hd->scsi_ints = ints;
    719 				return 0;
    720 			}
    721 		} else
    722 			goto abort;
    723 	} else
    724 		goto abort;
    725 
    726 	hd->scsi_ints = ints;
    727 
    728 	/*
    729 	 * Next SCSI Transfer
    730 	 */
    731 
    732 	while ((hd->scsi_psns & PSNS_REQ) == 0) {
    733 		DELAY(1);
    734 	}
    735 
    736 	hs->sc_phase = hd->scsi_psns & PHASE;
    737 
    738 	if ((hs->sc_phase == DATA_OUT_PHASE) ||
    739 	    (hs->sc_phase == DATA_IN_PHASE)) {
    740 		len = hs->sc_len;
    741 		buf = hs->sc_buf;
    742 	} else if (hs->sc_phase == CMD_PHASE) {
    743 		len = hs->sc_cdblen;
    744 		buf = hs->sc_cdb;
    745 	} else if (hs->sc_phase == STATUS_PHASE) {
    746 		len = 1;
    747 		buf = &hs->sc_stat;
    748 	} else {
    749 		len = 1;
    750 		buf = hs->sc_msg;
    751 	}
    752 
    753 	ixfer_start(hd, len, hs->sc_phase, 0);
    754 	if (hs->sc_phase & PHASE_IO)
    755 		ixfer_in(hd, len, buf);
    756 	else
    757 		ixfer_out(hd, len, buf);
    758 
    759 	return 0;
    760 
    761 	/*
    762 	 * SCSI Abort
    763 	 */
    764  abort:
    765 	/* SCSI IO failed */
    766 	scabort(hs);
    767 	hd->scsi_ints = ints;
    768 	*(hs->sc_lock) = SC_IO_FAILED;
    769 	return -1;
    770 }
    771