xref: /csrg-svn/sys/luna68k/dev/sc.c (revision 55175)
154004Sfujita /*
254004Sfujita  * Copyright (c) 1992 OMRON Corporation.
354004Sfujita  * Copyright (c) 1992 The Regents of the University of California.
454004Sfujita  * All rights reserved.
554004Sfujita  *
654004Sfujita  * This code is derived from software contributed to Berkeley by
754004Sfujita  * OMRON Corporation.
854004Sfujita  *
954004Sfujita  * %sccs.include.redist.c%
1054004Sfujita  *
11*55175Saki  *	@(#)sc.c	7.2 (Berkeley) 07/13/92
1254004Sfujita  */
1354004Sfujita 
1454004Sfujita /*
1554004Sfujita  * sc.c -- FUJITSU MB89352 SCSI Protocole Controller (SPC) Device Driver
1654004Sfujita  *
1754004Sfujita  * remaked by A.Fujita,		Mar-22-1992
1854004Sfujita  * remaked again by A.Fujita,	Apr-16-1992
1954004Sfujita  */
2054004Sfujita 
2154004Sfujita #define DEBUG_FUNC
2254004Sfujita 
2354004Sfujita #include "sc.h"
2454004Sfujita #if NSC > 0
2554004Sfujita 
2654004Sfujita #include "sys/param.h"
2754004Sfujita #include "sys/systm.h"
2854004Sfujita #include "sys/buf.h"
2954004Sfujita #include "device.h"
3054004Sfujita 
3154004Sfujita #include "scsireg.h"
3254004Sfujita #include "scsivar.h"
3354004Sfujita 
3454004Sfujita /*
3554004Sfujita  * SC Driver Options
3654004Sfujita  */
3754004Sfujita 
3854004Sfujita #define	QUADBYTES	/* 4 bytes access to SPC DREG Reg. */
3954004Sfujita #define	NODISCONNECT	/* not used SCSI DISCONNECT Ops. */
4054004Sfujita #undef	XFER_ENABLE	/* using interrupt for DREG access */
4154004Sfujita 
4254004Sfujita 
4354004Sfujita #define SCSI_IPL	2
4454004Sfujita #define SCSI_ID		7
4554004Sfujita 
4654004Sfujita extern char *hexstr();
4754004Sfujita 
4854004Sfujita int	scinit(), scstart(), scintr();
4954004Sfujita void	screset();
5054004Sfujita struct	driver scdriver = {
5154004Sfujita 	scinit, "sc", scstart, (int (*)()) 0, scintr, (int (*)()) 0
5254004Sfujita };
5354004Sfujita 
5454004Sfujita struct	scsi_softc scsi_softc[NSC];
5554004Sfujita 
5654004Sfujita 
5754004Sfujita #define	SC_TIMEOUT	0x01400000	/* (20971520) */
5854004Sfujita 
5954004Sfujita 
6054004Sfujita /*
6154004Sfujita  * for DEBUG
6254004Sfujita  */
6354004Sfujita 
6454004Sfujita char *
6554004Sfujita scsi_status(stat)
6654004Sfujita 	u_char stat;
6754004Sfujita {
6854004Sfujita 	if ((stat & 0x1e) == 0)
6954004Sfujita 		return("Good");
7054004Sfujita 	else if ((stat & 0x1e) == STS_CHECKCOND)
7154004Sfujita 		return("Check Condition");
7254004Sfujita 	else if ((stat & 0x1e) == STS_CONDMET)
7354004Sfujita 		return("Condition Met");
7454004Sfujita 	else if ((stat & 0x1e) == STS_BUSY)
7554004Sfujita 		return("Busy");
7654004Sfujita 	else if ((stat & 0x1e) == STS_INTERMED)
7754004Sfujita 		return("Intermediate status sent");
7854004Sfujita 	else if ((stat & 0x1e) == STS_EXT)
7954004Sfujita 		return("Extended status valid");
8054004Sfujita 	else
8154004Sfujita 		return("Unknown Status");
8254004Sfujita }
8354004Sfujita 
8454004Sfujita #ifdef DEBUG_FUNC
8554004Sfujita 
8654004Sfujita char *
8754004Sfujita scsi_command(cmd)
8854004Sfujita 	u_char cmd;
8954004Sfujita {
9054004Sfujita 	if (cmd == CMD_TEST_UNIT_READY)
9154004Sfujita 		return("TEST_UNIT_READY");
9254004Sfujita 	else if (cmd == CMD_REQUEST_SENSE)
9354004Sfujita 		return("REQUEST_SENSE");
9454004Sfujita 	else if (cmd == CMD_INQUIRY)
9554004Sfujita 		return("INQUIRY");
9654004Sfujita 	else if (cmd == CMD_READ)
9754004Sfujita 		return("READ");
9854004Sfujita 	else if (cmd == CMD_WRITE)
9954004Sfujita 		return("WRITE");
10054004Sfujita 	else if (cmd == CMD_READ_EXT)
10154004Sfujita 		return("READ EXT");
10254004Sfujita 	else if (cmd == CMD_WRITE_EXT)
10354004Sfujita 		return("WRITE_EXT");
10454004Sfujita 	else if (cmd == CMD_READ_CAPACITY)
10554004Sfujita 		return("READ_CAPACITY");
10654004Sfujita 	else
10754004Sfujita 		return(hexstr(cmd, 2));
10854004Sfujita }
10954004Sfujita 
11054004Sfujita char *
11154004Sfujita scsi_mesg(mesg)
11254004Sfujita 	u_char mesg;
11354004Sfujita {
11454004Sfujita 	if (mesg == MSG_CMD_COMPLETE)
11554004Sfujita 		return("Command Complete");
11654004Sfujita 	else if (mesg == MSG_EXT_MESSAGE)
11754004Sfujita 		return("Extended Message");
11854004Sfujita 	else if (mesg == MSG_SAVE_DATA_PTR)
11954004Sfujita 		return("Save Data Pointer");
12054004Sfujita 	else if (mesg == MSG_RESTORE_PTR)
12154004Sfujita 		return("Restore Pointer");
12254004Sfujita 	else if (mesg == MSG_DISCONNECT)
12354004Sfujita 		return("Disconnect");
12454004Sfujita 	else if (mesg == MSG_INIT_DETECT_ERROR)
12554004Sfujita 		return("Initiator Detected Error");
12654004Sfujita 	else if (mesg == MSG_ABORT)
12754004Sfujita 		return("Abort");
12854004Sfujita 	else if (mesg == MSG_REJECT)
12954004Sfujita 		return("Message Reject");
13054004Sfujita 	else if (mesg == MSG_NOOP)
13154004Sfujita 		return("No Operation");
13254004Sfujita 	else if (mesg == MSG_PARITY_ERROR)
13354004Sfujita 		return("Message Parity Error");
13454004Sfujita 	else if (mesg == MSG_BUS_DEVICE_RESET)
13554004Sfujita 		return("Bus Device Reset");
13654004Sfujita 	else if (mesg == MSG_IDENTIFY)
13754004Sfujita 		return("Identify");
13854004Sfujita 	else if (mesg == MSG_IDENTIFY_DR)
13954004Sfujita 		return("Identify (Disconnect)");
14054004Sfujita 	else
14154004Sfujita 		return("Unknown Message");
14254004Sfujita }
14354004Sfujita 
14454004Sfujita char *
14554004Sfujita phase_name(phase)
14654004Sfujita 	u_char phase;
14754004Sfujita {
14854004Sfujita 	if (phase == DATA_OUT_PHASE)
14954004Sfujita 		return("Data Out");
15054004Sfujita 	else if (phase == DATA_IN_PHASE)
15154004Sfujita 		return("Data In");
15254004Sfujita 	else if (phase == CMD_PHASE)
15354004Sfujita 		return("Command");
15454004Sfujita 	else if (phase == STATUS_PHASE)
15554004Sfujita 		return("Status");
15654004Sfujita 	else if (phase == BUS_FREE_PHASE)
15754004Sfujita 		return("Bus Free");
15854004Sfujita 	else if (phase == ARB_SEL_PHASE)
15954004Sfujita 		return("Arbitration/Select");
16054004Sfujita 	else if (phase == MESG_OUT_PHASE)
16154004Sfujita 		return("Message Out");
16254004Sfujita 	else if (phase == MESG_IN_PHASE)
16354004Sfujita 		return("Message In");
16454004Sfujita 	else
16554004Sfujita 		return("Unknown");
16654004Sfujita }
16754004Sfujita #endif
16854004Sfujita 
16954004Sfujita /*
17054004Sfujita  * Initialize SPC & Data Structure
17154004Sfujita  */
17254004Sfujita 
17354004Sfujita int
17454004Sfujita scinit(hc)
17554004Sfujita 	register struct hp_ctlr *hc;
17654004Sfujita {
17754004Sfujita 	register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
17854004Sfujita 	register int i;
17954004Sfujita 
18054004Sfujita 	hc->hp_ipl    = SCSI_IPL;
18154004Sfujita 	hs->sc_hc     = hc;
18254004Sfujita 	hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
18354004Sfujita 	hs->sc_wq.dq_forw = hs->sc_wq.dq_back = &hs->sc_wq;
18454004Sfujita 
18554004Sfujita 	hs->sc_flags  = 0;
18654004Sfujita 	hs->sc_phase  = BUS_FREE_PHASE;
18754004Sfujita 
18854004Sfujita 	hs->sc_stat   = 0;
18954004Sfujita 	hs->sc_msg[0] = 0;
19054004Sfujita 
19154004Sfujita 	scsi_init_buf();
19254004Sfujita 
19354004Sfujita 	screset(hc->hp_unit);
19454004Sfujita 
19554004Sfujita 	return(1);
19654004Sfujita }
19754004Sfujita 
19854004Sfujita void
19954004Sfujita screset(unit)
20054004Sfujita 	register int unit;
20154004Sfujita {
20254004Sfujita 	register struct scsi_softc *hs = &scsi_softc[unit];
20354004Sfujita 	volatile register struct scsidevice *hd =
20454004Sfujita 				(struct scsidevice *)hs->sc_hc->hp_addr;
20554004Sfujita 
20654004Sfujita 	printf("sc%d: ", unit);
20754004Sfujita 
20854004Sfujita 	/*
20954004Sfujita 	 * Disable interrupts then reset the FUJI chip.
21054004Sfujita 	 */
21154004Sfujita 
21254004Sfujita 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
21354004Sfujita 	hd->scsi_scmd = 0;
21454004Sfujita 	hd->scsi_pctl = 0;
21554004Sfujita 	hd->scsi_temp = 0;
21654004Sfujita 	hd->scsi_tch  = 0;
21754004Sfujita 	hd->scsi_tcm  = 0;
21854004Sfujita 	hd->scsi_tcl  = 0;
21954004Sfujita 	hd->scsi_ints = 0;
22054004Sfujita 
22154004Sfujita 	/* We can use Asynchronous Transfer only */
22254004Sfujita 	printf("async");
22354004Sfujita 
22454004Sfujita 	/*
22554004Sfujita 	 * Configure MB89352 with its SCSI address, all
22654004Sfujita 	 * interrupts enabled & appropriate parity.
22754004Sfujita 	 */
22854004Sfujita 	hd->scsi_bdid = SCSI_ID;
22954004Sfujita 	hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
23054004Sfujita 			SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
23154004Sfujita 			SCTL_INTR_ENAB;
23254004Sfujita 	printf(", parity");
23354004Sfujita 
23454004Sfujita 	DELAY(400);
23554004Sfujita 	hd->scsi_sctl &= ~SCTL_DISABLE;
23654004Sfujita 
23754004Sfujita 	printf(", scsi id %d\n", SCSI_ID);
23854004Sfujita }
23954004Sfujita 
24054004Sfujita 
24154004Sfujita /*
24254004Sfujita  * SPC Arbitration/Selection routine
24354004Sfujita  */
24454004Sfujita 
24554004Sfujita int
24654004Sfujita issue_select(hd, target, flags)
24754004Sfujita 	volatile register struct scsidevice *hd;
24854004Sfujita 	u_char target;
24954004Sfujita 	int flags;
25054004Sfujita {
25154004Sfujita #ifndef NODISCONNECT
25254004Sfujita 	if (flags & DQ_DISCONNECT) {
25354004Sfujita 		hd->scsi_scmd = SCMD_SET_ATN;
25454004Sfujita 	}
25554004Sfujita #endif
25654004Sfujita 
25754004Sfujita 	hd->scsi_pctl = 0;
25854004Sfujita 	hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
25954004Sfujita 
26054004Sfujita 	/* select timeout is hardcoded to 2ms */
26154004Sfujita 	hd->scsi_tch = 0;
26254004Sfujita 	hd->scsi_tcm = 32;
26354004Sfujita 	hd->scsi_tcl = 4;
26454004Sfujita 
26554004Sfujita 	hd->scsi_scmd = SCMD_SELECT;
26654004Sfujita 
26754004Sfujita 	return (1);
26854004Sfujita }
26954004Sfujita 
27054004Sfujita 
27154004Sfujita /*
27254004Sfujita  * SPC Manual Transfer routines
27354004Sfujita  */
27454004Sfujita 
27554004Sfujita /* not yet */
27654004Sfujita 
27754004Sfujita 
27854004Sfujita /*
27954004Sfujita  * SPC Program Transfer routines
28054004Sfujita  */
28154004Sfujita 
28254004Sfujita int
28354004Sfujita ixfer_start(hd, len, phase)
28454004Sfujita 	volatile register struct scsidevice *hd;
28554004Sfujita 	register int len;
28654004Sfujita 	register u_char phase;
28754004Sfujita {
28854004Sfujita 	register int wait = 0;
28954004Sfujita 
29054004Sfujita 	hd->scsi_sdgc = 0;
29154004Sfujita 
29254004Sfujita 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
29354004Sfujita 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
29454004Sfujita 	hd->scsi_tcl  =  (len & 0x0000ff);
29554004Sfujita 	hd->scsi_pctl = phase;
29654004Sfujita 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
29754004Sfujita 
29854004Sfujita 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
29954004Sfujita 		if (wait > SC_TIMEOUT) {
30054004Sfujita 			panic("ixfer_start: too long wait");
30154004Sfujita 		}
30254004Sfujita 		wait++;
30354004Sfujita 		DELAY(1);
30454004Sfujita 	}
30554004Sfujita }
30654004Sfujita 
30754004Sfujita int
30854004Sfujita ixfer_out(hd, len, buf)
30954004Sfujita 	volatile register struct scsidevice *hd;
31054004Sfujita 	register int len;
31154004Sfujita 	register u_char *buf;
31254004Sfujita {
31354004Sfujita 	u_char *t = buf;
31454004Sfujita 	register int wait = 0;
31554004Sfujita #ifdef QUADBYTES
31654004Sfujita 	register int qwait = 0;
31754004Sfujita 	register int l_len = len >> 3;
31854004Sfujita 	register u_long * l_buf = (u_long *) buf;
31954004Sfujita 
32054004Sfujita 	for(; l_len > 0; l_len--) {
32154004Sfujita 		while ((hd->scsi_ssts & SSTS_DREG_EMPTY) == 0) {
32254004Sfujita 			if (qwait > SC_TIMEOUT) {
32354004Sfujita 				printf("ixfer_out: quad time out\n");
32454004Sfujita 				printf("ixfer_out: %d bytes sended\n",
32554004Sfujita 				       (((u_char *) l_buf) - t));
32654004Sfujita 				printf("ixfer_out: TC = %d\n",
32754004Sfujita 				       ( hd->scsi_tch << 16 ) |
32854004Sfujita 				       ( hd->scsi_tcm <<  8 ) |
32954004Sfujita 				       ( hd->scsi_tcl ));
33054004Sfujita 				return(-1);
33154004Sfujita 			}
33254004Sfujita 			qwait++;
33354004Sfujita 			DELAY(1);
33454004Sfujita 		}
33554004Sfujita 		*((u_long *) &hd->scsi_dreg) = *l_buf++;
33654004Sfujita 		*((u_long *) &hd->scsi_dreg) = *l_buf++;
33754004Sfujita 	}
33854004Sfujita 
33954004Sfujita 	len &= 0x07;
34054004Sfujita 	buf = (u_char *) l_buf;
34154004Sfujita #endif
34254004Sfujita 	for(; len > 0; len--) {
34354004Sfujita 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
34454004Sfujita 			if (wait > SC_TIMEOUT) {
34554004Sfujita 				printf("ixfer_out: time out\n");
34654004Sfujita 				printf("ixfer_out: %d bytes sended\n",
34754004Sfujita 				       (buf - t));
34854004Sfujita 				return(-1);
34954004Sfujita 			}
35054004Sfujita 			wait++;
35154004Sfujita 			DELAY(1);
35254004Sfujita 		}
35354004Sfujita 		hd->scsi_dreg = *buf++;
35454004Sfujita 	}
35554004Sfujita 
35654004Sfujita #ifdef QUADBYTES
35754004Sfujita 	return(qwait);
35854004Sfujita #else
35954004Sfujita 	return(wait);
36054004Sfujita #endif
36154004Sfujita }
36254004Sfujita 
36354004Sfujita int
36454004Sfujita ixfer_in(hd, len, buf)
36554004Sfujita 	volatile register struct scsidevice *hd;
36654004Sfujita 	register int len;
36754004Sfujita 	register u_char *buf;
36854004Sfujita {
36954004Sfujita 	u_char *t = buf;
37054004Sfujita 	register int wait = 0;
37154004Sfujita #ifdef QUADBYTES
37254004Sfujita 	register int qwait = 0;
37354004Sfujita 	register int l_len = len >> 3;
37454004Sfujita 	register u_long * l_buf = (u_long *) buf;
37554004Sfujita 
37654004Sfujita 	for(; l_len > 0; l_len--) {
37754004Sfujita 		while ((hd->scsi_ssts & SSTS_DREG_FULL) == 0) {
37854004Sfujita 			if (qwait > SC_TIMEOUT) {
37954004Sfujita 				printf("ixfer_in: quad time out\n");
38054004Sfujita 				printf("ixfer_in: %d bytes recieved\n",
38154004Sfujita 				       (((u_char *) l_buf) - t));
38254004Sfujita 				return(-1);
38354004Sfujita 			}
38454004Sfujita 			qwait++;
38554004Sfujita 			DELAY(1);
38654004Sfujita 		}
38754004Sfujita 		*l_buf++ = *((u_long *) &hd->scsi_dreg);
38854004Sfujita 		*l_buf++ = *((u_long *) &hd->scsi_dreg);
38954004Sfujita 	}
39054004Sfujita 
39154004Sfujita 	len &= 0x07;
39254004Sfujita 	buf = (u_char *) l_buf;
39354004Sfujita #endif
39454004Sfujita 	for (; len > 0; len--) {
39554004Sfujita 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
39654004Sfujita 			if (wait > SC_TIMEOUT) {
39754004Sfujita 				printf("ixfer_in: time out\n");
39854004Sfujita 				printf("ixfer_in: %d bytes recieved\n",
39954004Sfujita 				       (buf - t));
40054004Sfujita 				return(-1);
40154004Sfujita 			}
40254004Sfujita 			wait++;
40354004Sfujita 			DELAY(1);
40454004Sfujita 		}
40554004Sfujita 		*buf++ = hd->scsi_dreg;
40654004Sfujita 	}
40754004Sfujita 
40854004Sfujita 
40954004Sfujita #ifdef QUADBYTES
41054004Sfujita 	return(qwait);
41154004Sfujita #else
41254004Sfujita 	return(wait);
41354004Sfujita #endif
41454004Sfujita }
41554004Sfujita 
41654004Sfujita 
41754004Sfujita #ifdef XFER_ENABLE
41854004Sfujita /*
41954004Sfujita  * SPC Interrupt base Transfer Routines
42054004Sfujita  */
42154004Sfujita 
42254004Sfujita int
42354004Sfujita txfer_start(hd, len, phase)
42454004Sfujita 	volatile register struct scsidevice *hd;
42554004Sfujita 	register int len;
42654004Sfujita 	register u_char phase;
42754004Sfujita {
42854004Sfujita 	register int wait = 0;
42954004Sfujita 
43054004Sfujita 	hd->scsi_sdgc = SDGC_XFER_ENAB;		/* for interrupt */
43154004Sfujita 
43254004Sfujita 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
43354004Sfujita 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
43454004Sfujita 	hd->scsi_tcl  =  (len & 0x0000ff);
43554004Sfujita 	hd->scsi_pctl = phase;
43654004Sfujita 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
43754004Sfujita 
43854004Sfujita 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
43954004Sfujita 		if (wait > SC_TIMEOUT) {
44054004Sfujita 			panic("ixfer_start: too long wait");
44154004Sfujita 		}
44254004Sfujita 		wait++;
44354004Sfujita 		DELAY(1);
44454004Sfujita 	}
44554004Sfujita }
44654004Sfujita 
44754004Sfujita int
44854004Sfujita txfer_in(ctlr)
44954004Sfujita 	register int ctlr;
45054004Sfujita {
45154004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
45254004Sfujita 	volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr;
45354004Sfujita 	register struct scsi_queue *dq = hs->sc_sq.dq_forw;
45454004Sfujita #ifdef QUADBYTES
45554004Sfujita 	register u_long *lp;
45654004Sfujita 
45754004Sfujita 	if (hd->scsi_ssts & SSTS_DREG_FULL) {
45854004Sfujita 		lp = (u_long *) dq->dq_xferp;
45954004Sfujita 
46054004Sfujita 		*lp++ = *((u_long *) &hd->scsi_dreg);
46154004Sfujita 		*lp++ = *((u_long *) &hd->scsi_dreg);
46254004Sfujita 
46354004Sfujita 		dq->dq_xferp = (u_char *) lp;
46454004Sfujita 		dq->dq_xfercnt -= 8;
46554004Sfujita 
46654004Sfujita 		goto xfer_done;
46754004Sfujita 	}
46854004Sfujita #endif
46954004Sfujita 
47054004Sfujita 	*dq->dq_xferp++ = hd->scsi_dreg;
47154004Sfujita 	dq->dq_xfercnt--;
47254004Sfujita 
47354004Sfujita  xfer_done:
47454004Sfujita #ifdef DEBUGPRINT
47554004Sfujita 	if (dq->dq_xfercnt == 0) {
47654004Sfujita 		dbgprintf("txfer_in: ");
47754004Sfujita 		dbgprintf("dq->dq_bp->b_un.b_addr = 0x%s, ", hexstr(dq->dq_bp->b_un.b_addr, 8));
47854004Sfujita 		dbgprintf("dq->dq_xferp = 0x%s :", hexstr(dq->dq_xferp, 8));
47954004Sfujita 		dbgprintf("done\n");
48054004Sfujita 	}
48154004Sfujita #endif
48254004Sfujita }
48354004Sfujita #endif
48454004Sfujita 
48554004Sfujita /*
48654004Sfujita  * SCSI Job Handler
48754004Sfujita  */
48854004Sfujita 
48954004Sfujita int
49054004Sfujita scstart(ctlr)
49154004Sfujita 	int ctlr;
49254004Sfujita {
49354004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
49454004Sfujita 	volatile register struct scsidevice *hd =
49554004Sfujita 		(struct scsidevice *) hs->sc_hc->hp_addr;
49654004Sfujita 	register struct scsi_queue *dq = hs->sc_sq.dq_forw;
49754004Sfujita 
49854004Sfujita 	dq->dq_imax =  0;
49954004Sfujita 	dq->dq_imin = -1;
50054004Sfujita 	dq->dq_omax =  0;
50154004Sfujita 	dq->dq_omin = -1;
50254004Sfujita 
50354004Sfujita 	hs->sc_flags  = 0;
50454004Sfujita 	hs->sc_phase  = ARB_SEL_PHASE;
50554004Sfujita 
50654004Sfujita 	hs->sc_stat   = 0;
50754004Sfujita 	hs->sc_msg[0] = 0;
50854004Sfujita 
50954004Sfujita #ifdef DEBUGPRINT
51054004Sfujita 	dbgprintf("\n");
51154004Sfujita 	dbgprintf("scstart: ID = %d\n", dq->dq_slave);
51254004Sfujita 	dbgprintf("scstart: cdb[0] = %s\n", scsi_command(dq->dq_cdb->cdb[0]));
51354004Sfujita 	dbgprintf("scstart: cdb[1] = 0x%s\n", hexstr(dq->dq_cdb->cdb[1], 2));
51454004Sfujita 	dbgprintf("scstart: cdb[2] = 0x%s\n", hexstr(dq->dq_cdb->cdb[2], 2));
51554004Sfujita 	dbgprintf("scstart: cdb[3] = 0x%s\n", hexstr(dq->dq_cdb->cdb[3], 2));
51654004Sfujita 	dbgprintf("scstart: cdb[4] = 0x%s\n", hexstr(dq->dq_cdb->cdb[4], 2));
51754004Sfujita 	dbgprintf("scstart: cdb[5] = 0x%s\n", hexstr(dq->dq_cdb->cdb[5], 2));
51854004Sfujita 	if (dq->dq_cdb->cdb[0] & 0xE0) {
51954004Sfujita 		dbgprintf("scstart: cdb[6] = 0x%s\n", hexstr(dq->dq_cdb->cdb[6], 2));
52054004Sfujita 		dbgprintf("scstart: cdb[7] = 0x%s\n", hexstr(dq->dq_cdb->cdb[7], 2));
52154004Sfujita 		dbgprintf("scstart: cdb[8] = 0x%s\n", hexstr(dq->dq_cdb->cdb[8], 2));
52254004Sfujita 		dbgprintf("scstart: cdb[9] = 0x%s\n", hexstr(dq->dq_cdb->cdb[9], 2));
52354004Sfujita 	}
52454004Sfujita 	dbgprintf("scstart: bp->b_bcount = %d\n", dq->dq_bp->b_bcount);
52554004Sfujita 	dbgprintf("scstart: %s\n", phase_name(hs->sc_phase));
52654004Sfujita #endif
52754004Sfujita 
52854004Sfujita 	issue_select(hd, dq->dq_slave, dq->dq_flags);
52954004Sfujita 
53054004Sfujita 	return(1);
53154004Sfujita }
53254004Sfujita 
53354004Sfujita int
53454004Sfujita _scintr()
53554004Sfujita {
53654004Sfujita 	register struct scsi_softc *hs;
53754004Sfujita 	volatile register struct scsidevice *hd;
53854004Sfujita 	register int ctlr;
53954004Sfujita 
54054004Sfujita 	for (ctlr = 0; ctlr < NSC; ctlr++) {
54154004Sfujita 		hs = &scsi_softc[ctlr];
54254004Sfujita 		hd = (struct scsidevice *) hs->sc_hc->hp_addr;
54354004Sfujita 
54454004Sfujita #ifdef XFER_ENABLE
54554004Sfujita 		if (((hd->scsi_psns & PHASE) == DATA_IN_PHASE) &&
54654004Sfujita 		    (hd->scsi_serr & SERR_XFER_OUT))
54754004Sfujita 			txfer_in(ctlr);
54854004Sfujita #endif
54954004Sfujita 
55054004Sfujita 		if (hd->scsi_ints != 0)
55154004Sfujita 			scintr(ctlr);
55254004Sfujita 	}
55354004Sfujita 
55454004Sfujita 	return;
55554004Sfujita }
55654004Sfujita 
55754004Sfujita int
55854004Sfujita scintr(ctlr)
55954004Sfujita 	register int ctlr;
56054004Sfujita {
56154004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
56254004Sfujita 	volatile register struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr;
56354004Sfujita 	register struct scsi_queue *dq = hs->sc_sq.dq_forw;
56454004Sfujita 	register u_char ints, temp;
56554004Sfujita 	register int i, slave;
56654004Sfujita 	int wait, len;
56754004Sfujita 	u_char *buf;
56854004Sfujita 
56954004Sfujita 	ints = hd->scsi_ints;
57054004Sfujita 
57154004Sfujita #ifdef DEBUGPRINT
57254004Sfujita 	dbgprintf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x",
57354004Sfujita 	       ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
57454004Sfujita 	if (hs->sc_phase == CMD_PHASE)
57554004Sfujita 		dbgprintf("   [%s]", scsi_command(dq->dq_cdb->cdb[0]));
57654004Sfujita 	if (hs->sc_phase & PHASE_MSG)
57754004Sfujita 		dbgprintf("   [%s]", scsi_mesg(hs->sc_msg[0]));
57854004Sfujita 	dbgprintf("\n");
57954004Sfujita #endif
58054004Sfujita 
58154004Sfujita 	if (ints & INTS_DISCON) {
58254004Sfujita 		if (hs->sc_msg[0] == MSG_CMD_COMPLETE) {
58354004Sfujita 			hd->scsi_ints = ints;
58454004Sfujita 
58554004Sfujita 			if (hs->sc_lock != NULL) {
58654004Sfujita 				*(hs->sc_lock) = SC_IO_COMPLETE;
58754004Sfujita 			} else {
58854004Sfujita 				(dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat);
58954004Sfujita 			}
59054004Sfujita 
59154004Sfujita 			return;
59254004Sfujita #ifndef NODISCONNECT
59354004Sfujita 		} else if (hs->sc_msg[0] == MSG_DISCONNECT) {
59454004Sfujita #ifdef DEBUGPRINT
59554004Sfujita 			dbgprintf("scintr: DISCONNECT : ctlr = %d, slave = %d, cdb = %s\n",
59654004Sfujita 			       dq->dq_ctlr, dq->dq_slave, scsi_command(dq->dq_cdb->cdb[0]));
59754004Sfujita #endif
59854004Sfujita 
59954004Sfujita 			hd->scsi_ints = ints;
60054004Sfujita 
60154004Sfujita 			scpend(dq);
60254004Sfujita 
60354004Sfujita 			dq = hs->sc_sq.dq_forw;
60454004Sfujita 
60554004Sfujita 			if (dq != &hs->sc_sq)
60654004Sfujita 				(dq->dq_driver->d_start)(dq->dq_unit);
60754004Sfujita 
60854004Sfujita 			return;
60954004Sfujita #endif
61054004Sfujita 		} else
61154004Sfujita 			goto abort;
61254004Sfujita 
61354004Sfujita #ifndef NODISCONNECT
61454004Sfujita 	} else if (ints & INTS_RESEL) {
61554004Sfujita 		temp = hd->scsi_temp & ~(1 << SCSI_ID);
61654004Sfujita 		for (slave = 0; temp != 1; slave++) {
61754004Sfujita 			temp >>= 1;
61854004Sfujita 		}
61954004Sfujita 
62054004Sfujita 		hd->scsi_ints = ints;
62154004Sfujita 
62254004Sfujita 		scrschdl(ctlr, slave);
62354004Sfujita 
62454004Sfujita 		dq = hs->sc_sq.dq_forw;
62554004Sfujita #ifdef DEBUGPRINT
62654004Sfujita 		dbgprintf("\n");
62754004Sfujita 		dbgprintf("scintr: RESELECT : ctlr = %d, slave = %d, cdb = %s\n",
62854004Sfujita 		       dq->dq_ctlr, dq->dq_slave, scsi_command(dq->dq_cdb->cdb[0]));
62954004Sfujita #endif
63054004Sfujita #endif
63154004Sfujita 	} else if (ints & INTS_CMD_DONE) {
63254004Sfujita 		if (hs->sc_phase == BUS_FREE_PHASE)
63354004Sfujita 			goto abort;
63454004Sfujita 		else if (hs->sc_phase  == MESG_IN_PHASE) {
63554004Sfujita 			hd->scsi_scmd = SCMD_RST_ACK;
63654004Sfujita 
63754004Sfujita 			 if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) ||
63854004Sfujita 			     (hs->sc_msg[0] == MSG_DISCONNECT)) {
63954004Sfujita 				 hd->scsi_ints = ints;
64054004Sfujita 
64154004Sfujita 				 hs->sc_phase  = BUS_FREE_PHASE;
64254004Sfujita 
64354004Sfujita 				 return;
64454004Sfujita 			 }
64554004Sfujita 		}
64654004Sfujita 		if (hs->sc_flags & SC_SEL_TIMEOUT)
64754004Sfujita 			hs->sc_flags &= ~SC_SEL_TIMEOUT;
64854004Sfujita 	} else if (ints & INTS_SRV_REQ) {
64954004Sfujita 		if (hs->sc_phase != MESG_IN_PHASE)
65054004Sfujita 			goto abort;
65154004Sfujita 	} else if (ints & INTS_TIMEOUT) {
65254004Sfujita 		if (hs->sc_phase == ARB_SEL_PHASE) {
65354004Sfujita 			if (hs->sc_flags & SC_SEL_TIMEOUT) {
65454004Sfujita 				hd->scsi_ints = ints;
65554004Sfujita 				hs->sc_flags &= ~SC_SEL_TIMEOUT;
65654004Sfujita 				/* Such SCSI Device is not conected. */
65754004Sfujita 
65854004Sfujita 				if (hs->sc_lock != NULL) {
65954004Sfujita 					*(hs->sc_lock) = SC_DEV_NOT_FOUND;
66054004Sfujita 				} else {
66154004Sfujita 					(dq->dq_driver->d_intr)(dq->dq_unit, SC_DEV_NOT_FOUND);
66254004Sfujita 				}
66354004Sfujita 
66454004Sfujita 				return;
66554004Sfujita 			} else {
66654004Sfujita 				/* wait more 250 usec */
66754004Sfujita 				hs->sc_flags |= SC_SEL_TIMEOUT;
66854004Sfujita 				hd->scsi_temp = 0;
66954004Sfujita 				hd->scsi_tch  = 0;
67054004Sfujita 				hd->scsi_tcm  = 0x06;
67154004Sfujita 				hd->scsi_tcl  = 0x40;
67254004Sfujita 				hd->scsi_ints = ints;
67354004Sfujita 				return;
67454004Sfujita 			}
67554004Sfujita 		} else
67654004Sfujita 			goto abort;
67754004Sfujita 	} else
67854004Sfujita 		goto abort;
67954004Sfujita 
68054004Sfujita 	hd->scsi_ints = ints;
68154004Sfujita 
68254004Sfujita 	/*
68354004Sfujita 	 * Next SCSI Transfer
68454004Sfujita 	 */
68554004Sfujita 
68654004Sfujita 	wait = SC_TIMEOUT;
68754004Sfujita 	while ((hd->scsi_psns & PSNS_REQ) == 0) {
68854004Sfujita 		if (wait < 0) {
68954004Sfujita /*			hd->scsi_scmd = SCMD_SET_ATN;	*/
69054004Sfujita 			hd->scsi_scmd = SCMD_RST;
69154004Sfujita 			DELAY(40);			/* wait 25 micro sec */
69254004Sfujita 			hd->scsi_scmd = 0;
69354004Sfujita 
69454004Sfujita 			wait = SC_TIMEOUT;
69554004Sfujita 			while (wait-- > 0)
69654004Sfujita 				DELAY(1);
69754004Sfujita 
69854004Sfujita 			if (hs->sc_lock != NULL) {
69954004Sfujita 				*(hs->sc_lock) = SC_IO_TIMEOUT;
70054004Sfujita 			} else {
70154004Sfujita 				(dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_TIMEOUT);
70254004Sfujita 			}
70354004Sfujita 
70454004Sfujita 			return;
70554004Sfujita 		}
70654004Sfujita 		DELAY(1);
70754004Sfujita 		wait--;
70854004Sfujita 	}
70954004Sfujita 
71054004Sfujita 	hs->sc_phase = hd->scsi_psns & PHASE;
71154004Sfujita 
71254004Sfujita #ifdef DEBUGPRINT
71354004Sfujita 	dbgprintf("scintr: %s\n", phase_name(hs->sc_phase));
71454004Sfujita #endif
71554004Sfujita 
71654004Sfujita 	if ((hs->sc_phase == DATA_OUT_PHASE) || (hs->sc_phase == DATA_IN_PHASE)) {
71754004Sfujita 		len = ( hs->sc_lock != NULL ? hs->sc_len : dq->dq_bp->b_bcount );
71854004Sfujita 		buf = ( hs->sc_lock != NULL ? hs->sc_buf : (u_char *) dq->dq_bp->b_un.b_addr );
71954004Sfujita 	} else if (hs->sc_phase == CMD_PHASE) {
72054004Sfujita 		len = ( hs->sc_lock != NULL ? hs->sc_cdblen : dq->dq_cdb->len );
72154004Sfujita 		buf = ( hs->sc_lock != NULL ? hs->sc_cdb    : dq->dq_cdb->cdb );
72254004Sfujita 	} else if (hs->sc_phase == STATUS_PHASE) {
72354004Sfujita 		len = 1;
72454004Sfujita 		buf = &hs->sc_stat;
72554004Sfujita 	} else {
72654004Sfujita 		if (hs->sc_phase == MESG_OUT_PHASE) {
72754004Sfujita #ifndef NODISCONNECT
72854004Sfujita 			hs->sc_msg[0] = MSG_IDENTIFY_DR;
72954004Sfujita #else
73054004Sfujita 			hs->sc_msg[0] = MSG_IDENTIFY;
73154004Sfujita #endif
73254004Sfujita 		}
73354004Sfujita 		len = 1;
73454004Sfujita 		buf = hs->sc_msg;
73554004Sfujita 	}
73654004Sfujita 
73754004Sfujita #ifdef XFER_ENABLE
73854004Sfujita 	if ((hs->sc_lock == NULL) && (hs->sc_phase == DATA_IN_PHASE)) {
73954004Sfujita 		dq->dq_xferp   = buf;
74054004Sfujita 		dq->dq_xfercnt = len;
74154004Sfujita 		txfer_start(hd, len, hs->sc_phase);
74254004Sfujita 		return;
74354004Sfujita 	}
74454004Sfujita #endif
74554004Sfujita 
74654004Sfujita 	ixfer_start(hd, len, hs->sc_phase);
74754004Sfujita 	if (hs->sc_phase & PHASE_IO) {
74854004Sfujita 		if ((wait = ixfer_in(hd, len, buf)) == -1) {
74954004Sfujita 			goto time_out;
75054004Sfujita 		}
75154004Sfujita 		if (dq->dq_imin == -1)
75254004Sfujita 			dq->dq_imin = wait;
75354004Sfujita 		else
754*55175Saki 			dq->dq_imin = min(wait, dq->dq_imin);
755*55175Saki 		dq->dq_imax = max(wait, dq->dq_imax);
75654004Sfujita 	} else {
75754004Sfujita 		if ((wait = ixfer_out(hd, len, buf)) == -1) {
75854004Sfujita 			goto time_out;
75954004Sfujita 		}
76054004Sfujita 		if (dq->dq_omin == -1)
76154004Sfujita 			dq->dq_omin = wait;
76254004Sfujita 		else
763*55175Saki 			dq->dq_omin = min(wait, dq->dq_omin);
764*55175Saki 		dq->dq_omax = max(wait, dq->dq_omax);
76554004Sfujita 	}
76654004Sfujita 
76754004Sfujita 	return;
76854004Sfujita 
76954004Sfujita  time_out:
77054004Sfujita 	scabort(hs, hd);
77154004Sfujita 	printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Current Status\n",
77254004Sfujita 	       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
77354004Sfujita 
77454004Sfujita 	if (hs->sc_lock != NULL) {
77554004Sfujita 		*(hs->sc_lock) = SC_IO_TIMEOUT;
77654004Sfujita 	} else {
77754004Sfujita 		(dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_TIMEOUT);
77854004Sfujita 	}
77954004Sfujita 
78054004Sfujita 	return;
78154004Sfujita 
78254004Sfujita 	/*
78354004Sfujita 	 * SCSI Abort
78454004Sfujita 	 */
78554004Sfujita  abort:
78654004Sfujita 
78754004Sfujita 	/* SCSI IO failed */
78854004Sfujita 	scabort(hs, hd);
78954004Sfujita 	hd->scsi_ints = ints;
79054004Sfujita 
79154004Sfujita 	if (hs->sc_lock != NULL) {
79254004Sfujita 		*(hs->sc_lock) = SC_IO_FAILED;
79354004Sfujita 	} else {
79454004Sfujita 		(dq->dq_driver->d_intr)(dq->dq_unit, SC_IO_FAILED);
79554004Sfujita 	}
79654004Sfujita 
79754004Sfujita 	return;
79854004Sfujita }
79954004Sfujita 
80054004Sfujita int
80154004Sfujita scabort(hs, hd)
80254004Sfujita 	register struct scsi_softc *hs;
80354004Sfujita 	volatile register struct scsidevice *hd;
80454004Sfujita {
80554004Sfujita 	int len;
80654004Sfujita 	u_char junk;
80754004Sfujita 
80854004Sfujita #ifdef DEBUGPRINT
80954004Sfujita 	dbgprintall();
81054004Sfujita 	printf("\n");
81154004Sfujita #endif
81254004Sfujita 
81354004Sfujita 	printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Current Status\n",
81454004Sfujita 	       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
81554004Sfujita 
81654004Sfujita 	if (hd->scsi_ints != 0)
81754004Sfujita 		hd->scsi_ints = hd->scsi_ints;
81854004Sfujita 	printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Reset INTS reg.\n",
81954004Sfujita 	       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
82054004Sfujita 
82154004Sfujita 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
82254004Sfujita 		/* no longer connected to scsi target */
82354004Sfujita 		return;
82454004Sfujita 
82554004Sfujita 	/* get the number of bytes remaining in current xfer + fudge */
82654004Sfujita 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
82754004Sfujita 	printf("scabort: Current xfer count = %d\n", len);
82854004Sfujita 
82954004Sfujita 	/* for that many bus cycles, try to send an abort msg */
83054004Sfujita 	for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
83154004Sfujita /*
83254004Sfujita 		hd->scsi_scmd = SCMD_SET_ATN;
83354004Sfujita 		printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Set ATN\n",
83454004Sfujita 		       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
83554004Sfujita  */
83654004Sfujita 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
83754004Sfujita 			printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Wait for REQ\n",
83854004Sfujita 			       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
83954004Sfujita 			if (! (hd->scsi_ssts & SSTS_INITIATOR))
84054004Sfujita 				goto out;
84154004Sfujita 			DELAY(1);
84254004Sfujita 		}
84354004Sfujita /*
84454004Sfujita 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) {
84554004Sfujita 			hd->scsi_scmd = SCMD_RST_ATN;
84654004Sfujita 			printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Reset ATN\n",
84754004Sfujita 			       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
84854004Sfujita 		}
84954004Sfujita  */
85054004Sfujita 		hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
85154004Sfujita 		printf("scabort: Phase = %s\n", phase_name(hs->sc_phase));
85254004Sfujita 
85354004Sfujita 		if (hd->scsi_psns & PHASE_IO) {
85454004Sfujita 			/* one of the input phases - read & discard a byte */
85554004Sfujita 			hd->scsi_scmd = SCMD_SET_ACK;
85654004Sfujita 			printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Set ACK\n",
85754004Sfujita 			       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
85854004Sfujita 
85954004Sfujita 			while (hd->scsi_psns & PSNS_REQ) {
86054004Sfujita 				printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Wait for REQ\n",
86154004Sfujita 				       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
86254004Sfujita 				DELAY(1);
86354004Sfujita 			}
86454004Sfujita 
86554004Sfujita 			junk = hd->scsi_temp;
86654004Sfujita 			printf("scabort: TEMP = 0x%s\n", hexstr(junk, 2));
86754004Sfujita 		} else {
86854004Sfujita 			/* one of the output phases - send an abort msg */
86954004Sfujita 			hd->scsi_temp = MSG_ABORT;
87054004Sfujita 			hd->scsi_scmd = SCMD_SET_ACK;
87154004Sfujita 			printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Set ACK\n",
87254004Sfujita 			       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
87354004Sfujita 
87454004Sfujita 			while (hd->scsi_psns & PSNS_REQ) {
87554004Sfujita 				printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Wait for REQ\n",
87654004Sfujita 				       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
87754004Sfujita 				DELAY(1);
87854004Sfujita 			}
87954004Sfujita 		}
88054004Sfujita 
88154004Sfujita 		hd->scsi_scmd = SCMD_RST_ACK;
88254004Sfujita 		printf("scabort: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Reset ACK\n",
88354004Sfujita 		       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
88454004Sfujita 	}
88554004Sfujita out:
88654004Sfujita 	/*
88754004Sfujita 	 * Either the abort was successful & the bus is disconnected or
88854004Sfujita 	 * the device didn't listen.  If the latter, announce the problem.
88954004Sfujita 	 * Either way, reset the card & the SPC.
89054004Sfujita 	 */
89154004Sfujita 	if (len < 0 && hs)
89254004Sfujita 		printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
89354004Sfujita 			hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
89454004Sfujita 
89554004Sfujita 	while (hd->scsi_ints == 0)
89654004Sfujita 		DELAY(1);
89754004Sfujita 
89854004Sfujita 	hd->scsi_ints = hd->scsi_ints;
89954004Sfujita 
90054004Sfujita 	printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x   Current Status\n",
90154004Sfujita 	       hd->scsi_ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns);
90254004Sfujita 
90354004Sfujita 	printf("scabort: SCSI abort operation is done\n");
90454004Sfujita }
90554004Sfujita 
90654004Sfujita 
90754004Sfujita /*
90854004Sfujita  * SPC device queue handling
90954004Sfujita  */
91054004Sfujita 
91154004Sfujita int
91254004Sfujita screq(dq)
91354004Sfujita 	register struct scsi_queue *dq;
91454004Sfujita {
91554004Sfujita 	register struct scsi_softc *hs = &scsi_softc[dq->dq_ctlr];
91654004Sfujita 	register struct scsi_queue *hq = &hs->sc_sq;
91754004Sfujita 
91854004Sfujita 	insque(dq, hq->dq_back);
91954004Sfujita 
92054004Sfujita 	if (dq->dq_back == hq) {
92154004Sfujita #ifdef QUE_DEBUG
92254004Sfujita 		printf("screq: slave = %d, command = %s\n",
92354004Sfujita 		       hq->dq_forw->dq_slave,
92454004Sfujita 		       scsi_command(hq->dq_forw->dq_cdb->cdb[0]));
92554004Sfujita #endif
92654004Sfujita 		return(1);
92754004Sfujita 	}
92854004Sfujita 
92954004Sfujita 	return(0);
93054004Sfujita }
93154004Sfujita 
93254004Sfujita #ifndef NODISCONNECT
93354004Sfujita int
93454004Sfujita scpend(dq)
93554004Sfujita 	register struct scsi_queue *dq;
93654004Sfujita {
93754004Sfujita 	register struct scsi_softc *hs = &scsi_softc[dq->dq_ctlr];
93854004Sfujita 	register struct scsi_queue *hq = &hs->sc_sq;
93954004Sfujita 	register struct scsi_queue *wq = &hs->sc_wq;
94054004Sfujita 
94154004Sfujita 	remque(dq);
94254004Sfujita 
94354004Sfujita 	insque(dq, wq->dq_back);
94454004Sfujita }
94554004Sfujita 
94654004Sfujita int
94754004Sfujita scrschdl(ctlr, slave)
94854004Sfujita 	register int ctlr;
94954004Sfujita 	register int slave;
95054004Sfujita {
95154004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
95254004Sfujita 	register struct scsi_queue *wq = &hs->sc_wq;
95354004Sfujita 	register struct scsi_queue *hq = &hs->sc_sq;
95454004Sfujita 	register struct scsi_queue *dq;
95554004Sfujita 
95654004Sfujita 	for (dq = wq->dq_forw; dq != wq; dq = dq->dq_forw) {
95754004Sfujita 		if (dq->dq_slave == slave)
95854004Sfujita 			goto found;
95954004Sfujita 	}
96054004Sfujita 
96154004Sfujita 	return(0);
96254004Sfujita 
96354004Sfujita  found:
96454004Sfujita 	remque(dq);
96554004Sfujita 	insque(dq, hq);
96654004Sfujita 
96754004Sfujita 	return(1);
96854004Sfujita }
96954004Sfujita #endif
97054004Sfujita 
97154004Sfujita int
97254004Sfujita scfree(dq)
97354004Sfujita 	register struct scsi_queue *dq;
97454004Sfujita {
97554004Sfujita 	register struct scsi_softc *hs = &scsi_softc[dq->dq_ctlr];
97654004Sfujita 	register struct scsi_queue *hq = &hs->sc_sq;
97754004Sfujita 	int status = hs->sc_stat;
97854004Sfujita 
97954004Sfujita 	remque(dq);
98054004Sfujita 
98154004Sfujita 	hs->sc_flags  = 0;
98254004Sfujita 	hs->sc_phase  = BUS_FREE_PHASE;
98354004Sfujita 
98454004Sfujita 	hs->sc_stat   = 0;
98554004Sfujita 	hs->sc_msg[0] = 0;
98654004Sfujita 
98754004Sfujita 	if ((dq = hq->dq_forw) != hq) {
98854004Sfujita #ifdef QUE_DEBUG
98954004Sfujita 		printf("scfree: slave = %d, command = %s\n",
99054004Sfujita 		       dq->dq_slave,
99154004Sfujita 		       scsi_command(dq->dq_cdb->cdb[0]));
99254004Sfujita #endif
99354004Sfujita 		(dq->dq_driver->d_start)(dq->dq_unit);
99454004Sfujita 	}
99554004Sfujita 
99654004Sfujita 	return(status);
99754004Sfujita }
99854004Sfujita 
99954004Sfujita /*
100054004Sfujita  * SCSI common interface
100154004Sfujita  */
100254004Sfujita 
100354004Sfujita int scsi_lock[NSC];
100454004Sfujita 
100554004Sfujita int
100654004Sfujita scsi_result(unit, stat)
100754004Sfujita 	int unit, stat;
100854004Sfujita {
100954004Sfujita #ifdef SCSI_DEBUG
101054004Sfujita 	printf("scsi_result: stat = %s\n", scsi_status(stat));
101154004Sfujita #endif
101254004Sfujita 	if (stat < 0)
101354004Sfujita 		scsi_lock[unit] = stat;
101454004Sfujita 	else
101554004Sfujita 		scsi_lock[unit] = SC_IO_COMPLETE;
101654004Sfujita }
101754004Sfujita 
101854004Sfujita struct	driver scsi_driver = {
101954004Sfujita 	(int (*)()) 0, "scsi", (int (*)()) 0, (int (*)()) 0, scsi_result, (int (*)()) 0
102054004Sfujita };
102154004Sfujita 
102254004Sfujita #define SCSI_BUF 8
102354004Sfujita 
102454004Sfujita struct buf scsi_buf[SCSI_BUF];
102554004Sfujita 
102654004Sfujita int
102754004Sfujita scsi_init_buf()
102854004Sfujita {
102954004Sfujita 	register struct buf *rbp = &scsi_buf[0];
103054004Sfujita 	register int i;
103154004Sfujita 
103254004Sfujita 	rbp->av_forw = rbp->av_back = rbp;
103354004Sfujita 
103454004Sfujita 	for(i = 0; i < SCSI_BUF; i++)
103554004Sfujita 		scsi_free_buf(&scsi_buf[i]);
103654004Sfujita }
103754004Sfujita 
103854004Sfujita int
103954004Sfujita scsi_free_buf(bp)
104054004Sfujita 	register struct buf *bp;
104154004Sfujita {
104254004Sfujita 	register struct buf *rbp = &scsi_buf[0];
104354004Sfujita 
104454004Sfujita 	bp->av_forw = rbp;
104554004Sfujita 	bp->av_back = rbp->av_back;
104654004Sfujita 
104754004Sfujita 	rbp->av_back->av_forw = bp;
104854004Sfujita 	rbp->av_back = bp;
104954004Sfujita }
105054004Sfujita 
105154004Sfujita struct buf *
105254004Sfujita scsi_get_buf()
105354004Sfujita {
105454004Sfujita 	register struct buf *rbp = &scsi_buf[0];
105554004Sfujita 	register struct buf *bp = rbp->av_forw;
105654004Sfujita 
105754004Sfujita 	if (bp == rbp)
105854004Sfujita 		return((struct buf *) 0);
105954004Sfujita 
106054004Sfujita 	bp->av_forw->av_back = rbp;
106154004Sfujita 	rbp->av_forw = bp->av_forw;
106254004Sfujita 
106354004Sfujita 	return(bp);
106454004Sfujita }
106554004Sfujita 
106654004Sfujita struct scsi_queue scsi_entry[NSC];
106754004Sfujita 
106854004Sfujita int
106954004Sfujita scsi_immed_command(ctlr, slave, lun, cdb, buf, len)
107054004Sfujita 	int ctlr, slave, lun;
107154004Sfujita 	struct scsi_fmt_cdb *cdb;
107254004Sfujita 	u_char *buf;
107354004Sfujita 	unsigned len;
107454004Sfujita {
107554004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
107654004Sfujita 	volatile register struct scsidevice *hd =
107754004Sfujita 		(struct scsidevice *) hs->sc_hc->hp_addr;
107854004Sfujita 	register struct scsi_queue *dq = &scsi_entry[ctlr];
107954004Sfujita 	register struct buf *bp;
108054004Sfujita 	int s, status, wait = 30;
108154004Sfujita 
108254004Sfujita #ifdef SCSI_DEBUG
108354004Sfujita 	printf("scsi_immed_command( %d, %d, %d, cdb(%d,%s), buf, %d): Start\n",
108454004Sfujita 	       ctlr, slave, lun, cdb->len, scsi_command(cdb->cdb[0]), len);
108554004Sfujita #endif
108654004Sfujita 
108754004Sfujita 	if ((bp = scsi_get_buf()) == 0) {
108854004Sfujita 		return(SC_BUSY);
108954004Sfujita 	}
109054004Sfujita 
109154004Sfujita 	s = splbio();
109254004Sfujita 
109354004Sfujita 	bp->b_flags = B_BUSY;
109454004Sfujita 	bp->b_bcount = len;
109554004Sfujita 	bp->b_un.b_addr = (caddr_t) buf;
109654004Sfujita 
109754004Sfujita 	dq->dq_unit   = ctlr;
109854004Sfujita 	dq->dq_ctlr   = ctlr;
109954004Sfujita 	dq->dq_slave  = slave;
110054004Sfujita 	dq->dq_driver = &scsi_driver;
110154004Sfujita 	dq->dq_cdb    = cdb;
110254004Sfujita 	dq->dq_bp     = bp;
110354004Sfujita 
110454004Sfujita 	scsi_lock[ctlr] = SC_IN_PROGRESS;
110554004Sfujita 	if (screq(dq))
110654004Sfujita 		scstart(ctlr);
110754004Sfujita 
110854004Sfujita 	splx(s);
110954004Sfujita 
111054004Sfujita 	while (scsi_lock[ctlr] == SC_IN_PROGRESS) {
111154004Sfujita 		if (wait < 0) {
111254004Sfujita 			scabort(hs, hd);
111354004Sfujita 
111454004Sfujita 			s = splbio();
111554004Sfujita 			status = scfree(dq);
111654004Sfujita 			splx(s);
111754004Sfujita 
111854004Sfujita 			bp->b_flags = 0;
111954004Sfujita 
112054004Sfujita 			return(SC_IO_FAILED);
112154004Sfujita 		}
112254004Sfujita 
112354004Sfujita 		DELAY(100000);
112454004Sfujita 		wait--;
112554004Sfujita 	}
112654004Sfujita 
112754004Sfujita 	s = splbio();
112854004Sfujita 	status = scfree(dq);
112954004Sfujita 	splx(s);
113054004Sfujita 
113154004Sfujita 	if (scsi_lock[ctlr] < 0)
113254004Sfujita 		status = scsi_lock[ctlr];
113354004Sfujita 
113454004Sfujita 	scsi_free_buf(bp);
113554004Sfujita 
113654004Sfujita #ifdef SCSI_DEBUG
113754004Sfujita 		printf("scsi_immed_command: Status -- 0x%x\n", status);
113854004Sfujita #endif
113954004Sfujita 	return(status);
114054004Sfujita }
114154004Sfujita 
114254004Sfujita int
114354004Sfujita scsi_test_unit_rdy(ctlr, slave, lun)
114454004Sfujita 	int ctlr, slave, lun;
114554004Sfujita {
114654004Sfujita 	static struct scsi_fmt_cdb cdb = { 6, CMD_TEST_UNIT_READY };
114754004Sfujita 	int stat;
114854004Sfujita 
114954004Sfujita 	while ((stat = scsi_immed_command(ctlr, slave, lun,
115054004Sfujita 					  &cdb, (u_char *) 0, 0)) == SC_BUSY) {
115154004Sfujita 		DELAY(10000);
115254004Sfujita 	}
115354004Sfujita 
115454004Sfujita 	return(stat);
115554004Sfujita }
115654004Sfujita 
115754004Sfujita int
115854004Sfujita scsi_request_sense(ctlr, slave, lun, buf, len)
115954004Sfujita 	int ctlr, slave, lun;
116054004Sfujita 	u_char *buf;
116154004Sfujita 	unsigned len;
116254004Sfujita {
116354004Sfujita 	register struct scsi_softc *hs = &scsi_softc[ctlr];
116454004Sfujita 	volatile register struct scsidevice *hd =
116554004Sfujita 		(struct scsidevice *) hs->sc_hc->hp_addr;
116654004Sfujita 	static struct scsi_fmt_cdb req_cmd = { 6, CMD_REQUEST_SENSE };
116754004Sfujita 	int s, status, lock;
116854004Sfujita 
116954004Sfujita #ifdef REQ_DEBUG
117054004Sfujita 	printf("scsi_request_sense( %d, %d, %d, buf, %d) -- Start\n",
117154004Sfujita 	       ctlr, slave, lun, len);
117254004Sfujita #endif
117354004Sfujita 
117454004Sfujita         req_cmd.cdb[1] = lun;
117554004Sfujita         req_cmd.cdb[4] = len;
117654004Sfujita 
117754004Sfujita 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
117854004Sfujita 		return(0);
117954004Sfujita 
118054004Sfujita 	s = splbio();
118154004Sfujita 
118254004Sfujita 	hs->sc_flags  = 0;
118354004Sfujita 	hs->sc_phase  = ARB_SEL_PHASE;
118454004Sfujita 
118554004Sfujita 	hs->sc_cdb    = req_cmd.cdb;
118654004Sfujita 	hs->sc_cdblen = req_cmd.len;
118754004Sfujita 	hs->sc_buf    = buf;
118854004Sfujita 	hs->sc_len    = len;
118954004Sfujita 
119054004Sfujita 	hs->sc_stat   = 0;
119154004Sfujita 	hs->sc_msg[0] = 0;
119254004Sfujita 
119354004Sfujita 	lock = SC_IN_PROGRESS;
119454004Sfujita 	hs->sc_lock   = &lock;
119554004Sfujita 
119654004Sfujita 	issue_select(hd, slave, 0);
119754004Sfujita 
119854004Sfujita 	spl0();
119954004Sfujita 
120054004Sfujita 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
120154004Sfujita 		DELAY(10);
120254004Sfujita 
120354004Sfujita 	splbio();
120454004Sfujita 
120554004Sfujita 	hs->sc_flags  = 0;
120654004Sfujita 	hs->sc_phase  = BUS_FREE_PHASE;
120754004Sfujita 
120854004Sfujita 	hs->sc_cdb    = NULL;
120954004Sfujita 	hs->sc_cdblen = 0;
121054004Sfujita 	hs->sc_buf    = NULL;
121154004Sfujita 	hs->sc_len    = 0;
121254004Sfujita 	hs->sc_lock   = NULL;
121354004Sfujita 
121454004Sfujita 	status = hs->sc_stat;
121554004Sfujita 
121654004Sfujita 	hs->sc_stat   = 0;
121754004Sfujita 	hs->sc_msg[0] = 0;
121854004Sfujita 
121954004Sfujita 	splx(s);
122054004Sfujita 
122154004Sfujita 	if (lock == SC_IO_COMPLETE) {
122254004Sfujita #ifdef REQ_DEBUG
122354004Sfujita 		printf("scsi_request_sense: Status -- 0x%x\n", status);
122454004Sfujita #endif
122554004Sfujita 		return(status);
122654004Sfujita 	} else {
122754004Sfujita 		return(lock);
122854004Sfujita 	}
122954004Sfujita }
123054004Sfujita #endif
1231