xref: /csrg-svn/sys/hp300/dev/scsi.c (revision 45788)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
341480Smckusick  * All rights reserved.
441480Smckusick  *
541480Smckusick  * This code is derived from software contributed to Berkeley by
641480Smckusick  * Van Jacobson of Lawrence Berkeley Laboratory.
741480Smckusick  *
841480Smckusick  * %sccs.include.redist.c%
941480Smckusick  *
10*45788Sbostic  *	@(#)scsi.c	7.3 (Berkeley) 12/16/90
1141480Smckusick  */
1241480Smckusick 
1341480Smckusick /*
1441480Smckusick  * HP9000/3xx 98658 SCSI host adaptor driver.
1541480Smckusick  */
1641480Smckusick #include "scsi.h"
1741480Smckusick #if NSCSI > 0
1841480Smckusick 
1941480Smckusick #ifndef lint
2045514Smckusick static char rcsid[] = "$Header: scsi.c,v 1.3 90/10/10 14:55:08 mike Exp $";
2141480Smckusick #endif
2241480Smckusick 
23*45788Sbostic #include "sys/param.h"
24*45788Sbostic #include "sys/systm.h"
25*45788Sbostic #include "sys/buf.h"
2641480Smckusick #include "device.h"
27*45788Sbostic 
2841480Smckusick #include "scsivar.h"
2941480Smckusick #include "scsireg.h"
3041480Smckusick #include "dmavar.h"
3141480Smckusick 
32*45788Sbostic #include "../include/cpu.h"
33*45788Sbostic #include "../hp300/isr.h"
3441480Smckusick 
3541480Smckusick extern void isrlink();
3641480Smckusick extern void printf();
3741480Smckusick extern void _insque();
3841480Smckusick extern void _remque();
3941480Smckusick extern void bzero();
4041480Smckusick 
4141480Smckusick int	scsiinit(), scsigo(), scsiintr(), scsixfer();
4241480Smckusick void	scsistart(), scsidone(), scsifree(), scsireset();
4341480Smckusick struct	driver scsidriver = {
4441480Smckusick 	scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr,
4541480Smckusick 	(int (*)())scsidone,
4641480Smckusick };
4741480Smckusick 
4841480Smckusick struct	scsi_softc scsi_softc[NSCSI];
4941480Smckusick struct	isr scsi_isr[NSCSI];
5041480Smckusick 
5141480Smckusick int scsi_cmd_wait = 512;	/* microsec wait per step of 'immediate' cmds */
5241480Smckusick int scsi_data_wait = 512;	/* wait per data in/out step */
5341480Smckusick int scsi_nosync = 1;		/* inhibit sync xfers if 1 */
5445514Smckusick int scsi_pridma = 0;		/* use "priority" dma */
5541480Smckusick 
5641480Smckusick #ifdef DEBUG
5741480Smckusick int	scsi_debug = 0;
5841480Smckusick #define WAITHIST
5941480Smckusick #endif
6041480Smckusick 
6141480Smckusick #ifdef WAITHIST
6245514Smckusick #define MAXWAIT	1022
6341480Smckusick u_int	ixstart_wait[MAXWAIT+2];
6441480Smckusick u_int	ixin_wait[MAXWAIT+2];
6541480Smckusick u_int	ixout_wait[MAXWAIT+2];
6641480Smckusick u_int	mxin_wait[MAXWAIT+2];
6741480Smckusick u_int	cxin_wait[MAXWAIT+2];
6841480Smckusick u_int	fxfr_wait[MAXWAIT+2];
6941480Smckusick u_int	sgo_wait[MAXWAIT+2];
7041480Smckusick #define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]);
7141480Smckusick #else
7241480Smckusick #define HIST(h,w)
7341480Smckusick #endif
7441480Smckusick 
7541480Smckusick #define	b_cylin		b_resid
7641480Smckusick 
7741480Smckusick static void
7841480Smckusick scsiabort(hs, hd, where)
7941480Smckusick 	register struct scsi_softc *hs;
8041480Smckusick 	volatile register struct scsidevice *hd;
8141480Smckusick 	char *where;
8241480Smckusick {
8341480Smckusick 	int len;
8441480Smckusick 	u_char junk;
8541480Smckusick 
8641480Smckusick 	printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
8741480Smckusick 		hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts,
8841480Smckusick 		hd->scsi_ints);
8941480Smckusick 
9041480Smckusick 	hd->scsi_ints = hd->scsi_ints;
9141480Smckusick 	hd->scsi_csr = 0;
9241480Smckusick 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
9341480Smckusick 		/* no longer connected to scsi target */
9441480Smckusick 		return;
9541480Smckusick 
9641480Smckusick 	/* get the number of bytes remaining in current xfer + fudge */
9741480Smckusick 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
9841480Smckusick 
9941480Smckusick 	/* for that many bus cycles, try to send an abort msg */
10041480Smckusick 	for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
10141480Smckusick 		hd->scsi_scmd = SCMD_SET_ATN;
10241480Smckusick 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
10341480Smckusick 			if (! (hd->scsi_ssts & SSTS_INITIATOR))
10441480Smckusick 				goto out;
10541480Smckusick 			DELAY(1);
10641480Smckusick 		}
10741480Smckusick 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
10841480Smckusick 			hd->scsi_scmd = SCMD_RST_ATN;
10941480Smckusick 		hd->scsi_pctl = hd->scsi_psns & PHASE;
11041480Smckusick 		if (hd->scsi_psns & PHASE_IO) {
11141480Smckusick 			/* one of the input phases - read & discard a byte */
11241480Smckusick 			hd->scsi_scmd = SCMD_SET_ACK;
11341480Smckusick 			if (hd->scsi_tmod == 0)
11441480Smckusick 				while (hd->scsi_psns & PSNS_REQ)
11541480Smckusick 					DELAY(1);
11641480Smckusick 			junk = hd->scsi_temp;
11741480Smckusick 		} else {
11841480Smckusick 			/* one of the output phases - send an abort msg */
11941480Smckusick 			hd->scsi_temp = MSG_ABORT;
12041480Smckusick 			hd->scsi_scmd = SCMD_SET_ACK;
12141480Smckusick 			if (hd->scsi_tmod == 0)
12241480Smckusick 				while (hd->scsi_psns & PSNS_REQ)
12341480Smckusick 					DELAY(1);
12441480Smckusick 		}
12541480Smckusick 		hd->scsi_scmd = SCMD_RST_ACK;
12641480Smckusick 	}
12741480Smckusick out:
12841480Smckusick 	/*
12941480Smckusick 	 * Either the abort was successful & the bus is disconnected or
13041480Smckusick 	 * the device didn't listen.  If the latter, announce the problem.
13141480Smckusick 	 * Either way, reset the card & the SPC.
13241480Smckusick 	 */
13341480Smckusick 	if (len < 0 && hs)
13441480Smckusick 		printf("scsi%d: abort failed.  phase=0x%x, ssts=0x%x\n",
13541480Smckusick 			hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
13641480Smckusick 
13741480Smckusick 	if (! ((junk = hd->scsi_ints) & INTS_RESEL)) {
13841480Smckusick 		hd->scsi_sctl |= SCTL_CTRLRST;
13941480Smckusick 		DELAY(1);
14041480Smckusick 		hd->scsi_sctl &=~ SCTL_CTRLRST;
14141480Smckusick 		hd->scsi_hconf = 0;
14241480Smckusick 		hd->scsi_ints = hd->scsi_ints;
14341480Smckusick 	}
14441480Smckusick }
14541480Smckusick 
14641480Smckusick int
14741480Smckusick scsiinit(hc)
14841480Smckusick 	register struct hp_ctlr *hc;
14941480Smckusick {
15041480Smckusick 	register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
15141480Smckusick 	register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr;
15241480Smckusick 
15341480Smckusick 	if ((hd->scsi_id & ID_MASK) != SCSI_ID)
15441480Smckusick 		return(0);
15541480Smckusick 	hc->hp_ipl = SCSI_IPL(hd->scsi_csr);
15641480Smckusick 	hs->sc_hc = hc;
15741480Smckusick 	hs->sc_dq.dq_unit = hc->hp_unit;
15841480Smckusick 	hs->sc_dq.dq_driver = &scsidriver;
15941480Smckusick 	hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
16041480Smckusick 	scsi_isr[hc->hp_unit].isr_intr = scsiintr;
16141480Smckusick 	scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;
16241480Smckusick 	scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
16341480Smckusick 	isrlink(&scsi_isr[hc->hp_unit]);
16441480Smckusick 	scsireset(hc->hp_unit);
16541480Smckusick 	return(1);
16641480Smckusick }
16741480Smckusick 
16841480Smckusick void
16941480Smckusick scsireset(unit)
17041480Smckusick 	register int unit;
17141480Smckusick {
17241480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
17341480Smckusick 	volatile register struct scsidevice *hd =
17441480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
17541480Smckusick 	u_int i;
17641480Smckusick 
17741480Smckusick 	if (hs->sc_flags & SCSI_ALIVE)
17841480Smckusick 		scsiabort(hs, hd, "reset");
17941480Smckusick 
18041480Smckusick 	printf("scsi%d: ", unit);
18141480Smckusick 
18241480Smckusick 	hd->scsi_id = 0xFF;
18341480Smckusick 	DELAY(100);
18441480Smckusick 	/*
18541480Smckusick 	 * Disable interrupts then reset the FUJI chip.
18641480Smckusick 	 */
18741480Smckusick 	hd->scsi_csr  = 0;
18841480Smckusick 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
18941480Smckusick 	hd->scsi_scmd = 0;
19041480Smckusick 	hd->scsi_tmod = 0;
19141480Smckusick 	hd->scsi_pctl = 0;
19241480Smckusick 	hd->scsi_temp = 0;
19341480Smckusick 	hd->scsi_tch  = 0;
19441480Smckusick 	hd->scsi_tcm  = 0;
19541480Smckusick 	hd->scsi_tcl  = 0;
19641480Smckusick 	hd->scsi_ints = 0;
19741480Smckusick 
19841480Smckusick 	if ((hd->scsi_id & ID_WORD_DMA) == 0) {
19941480Smckusick 		hs->sc_flags |= SCSI_DMA32;
20041480Smckusick 		printf("32 bit dma, ");
20141480Smckusick 	}
20241480Smckusick 
20341480Smckusick 	/* Determine Max Synchronous Transfer Rate */
20441480Smckusick 	if (scsi_nosync)
20541480Smckusick 		i = 3;
20641480Smckusick 	else
20741480Smckusick 		i = SCSI_SYNC_XFER(hd->scsi_hconf);
20841480Smckusick 	switch (i) {
20941480Smckusick 		case 0:
21041480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */
21141480Smckusick 			printf("250ns sync");
21241480Smckusick 			break;
21341480Smckusick 		case 1:
21441480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */
21541480Smckusick 			printf("375ns sync");
21641480Smckusick 			break;
21741480Smckusick 		case 2:
21841480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */
21941480Smckusick 			printf("500ns sync");
22041480Smckusick 			break;
22141480Smckusick 		case 3:
22241480Smckusick 			hs->sc_sync = 0;
22341480Smckusick 			printf("async");
22441480Smckusick 			break;
22541480Smckusick 		}
22641480Smckusick 
22741480Smckusick 	/*
22841480Smckusick 	 * Configure the FUJI chip with its SCSI address, all
22941480Smckusick 	 * interrupts enabled & appropriate parity.
23041480Smckusick 	 */
23141480Smckusick 	i = (~hd->scsi_hconf) & 0x7;
23241480Smckusick 	hs->sc_scsi_addr = 1 << i;
23341480Smckusick 	hd->scsi_bdid = i;
23441480Smckusick 	if (hd->scsi_hconf & HCONF_PARITY)
23541480Smckusick 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
23641480Smckusick 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
23741480Smckusick 				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
23841480Smckusick 	else {
23941480Smckusick 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
24041480Smckusick 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
24141480Smckusick 				SCTL_INTR_ENAB;
24241480Smckusick 		printf(", no parity");
24341480Smckusick 	}
24441480Smckusick 	hd->scsi_sctl &=~ SCTL_DISABLE;
24541480Smckusick 
24641480Smckusick 	printf(", scsi id %d\n", i);
24741480Smckusick 	hs->sc_flags |= SCSI_ALIVE;
24841480Smckusick }
24941480Smckusick 
25041480Smckusick static void
25141480Smckusick scsierror(hs, hd, ints)
25241480Smckusick 	register struct scsi_softc *hs;
25341480Smckusick 	volatile register struct scsidevice *hd;
25441480Smckusick 	u_char ints;
25541480Smckusick {
25641480Smckusick 	int unit = hs->sc_hc->hp_unit;
25741480Smckusick 	char *sep = "";
25841480Smckusick 
25941480Smckusick 	printf("scsi%d: ", unit);
26041480Smckusick 	if (ints & INTS_RST) {
26141480Smckusick 		DELAY(100);
26241480Smckusick 		if (hd->scsi_hconf & HCONF_SD)
26341480Smckusick 			printf("spurious RST interrupt");
26441480Smckusick 		else
26541480Smckusick 			printf("hardware error - check fuse");
26641480Smckusick 		sep = ", ";
26741480Smckusick 	}
26841480Smckusick 	if ((ints & INTS_HARD_ERR) || hd->scsi_serr) {
26941480Smckusick 		if (hd->scsi_serr & SERR_SCSI_PAR) {
27041480Smckusick 			printf("%sparity err", sep);
27141480Smckusick 			sep = ", ";
27241480Smckusick 		}
27341480Smckusick 		if (hd->scsi_serr & SERR_SPC_PAR) {
27441480Smckusick 			printf("%sSPC parity err", sep);
27541480Smckusick 			sep = ", ";
27641480Smckusick 		}
27741480Smckusick 		if (hd->scsi_serr & SERR_TC_PAR) {
27841480Smckusick 			printf("%sTC parity err", sep);
27941480Smckusick 			sep = ", ";
28041480Smckusick 		}
28141480Smckusick 		if (hd->scsi_serr & SERR_PHASE_ERR) {
28241480Smckusick 			printf("%sphase err", sep);
28341480Smckusick 			sep = ", ";
28441480Smckusick 		}
28541480Smckusick 		if (hd->scsi_serr & SERR_SHORT_XFR) {
28641480Smckusick 			printf("%ssync short transfer err", sep);
28741480Smckusick 			sep = ", ";
28841480Smckusick 		}
28941480Smckusick 		if (hd->scsi_serr & SERR_OFFSET) {
29041480Smckusick 			printf("%ssync offset error", sep);
29141480Smckusick 			sep = ", ";
29241480Smckusick 		}
29341480Smckusick 	}
29441480Smckusick 	if (ints & INTS_TIMEOUT)
29541480Smckusick 		printf("%sSPC select timeout error", sep);
29641480Smckusick 	if (ints & INTS_SRV_REQ)
29741480Smckusick 		printf("%sspurious SRV_REQ interrupt", sep);
29841480Smckusick 	if (ints & INTS_CMD_DONE)
29941480Smckusick 		printf("%sspurious CMD_DONE interrupt", sep);
30041480Smckusick 	if (ints & INTS_DISCON)
30141480Smckusick 		printf("%sspurious disconnect interrupt", sep);
30241480Smckusick 	if (ints & INTS_RESEL)
30341480Smckusick 		printf("%sspurious reselect interrupt", sep);
30441480Smckusick 	if (ints & INTS_SEL)
30541480Smckusick 		printf("%sspurious select interrupt", sep);
30641480Smckusick 	printf("\n");
30741480Smckusick }
30841480Smckusick 
30941480Smckusick static int
31041480Smckusick issue_select(hd, target, our_addr)
31141480Smckusick 	volatile register struct scsidevice *hd;
31241480Smckusick 	u_char target, our_addr;
31341480Smckusick {
31441480Smckusick 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
31541480Smckusick 		return (1);
31641480Smckusick 
31741480Smckusick 	if (hd->scsi_ints & INTS_DISCON)
31841480Smckusick 		hd->scsi_ints = INTS_DISCON;
31941480Smckusick 
32041480Smckusick 	hd->scsi_pctl = 0;
32141480Smckusick 	hd->scsi_temp = (1 << target) | our_addr;
32241480Smckusick 	/* select timeout is hardcoded to 2ms */
32341480Smckusick 	hd->scsi_tch = 0;
32441480Smckusick 	hd->scsi_tcm = 32;
32541480Smckusick 	hd->scsi_tcl = 4;
32641480Smckusick 
32741480Smckusick 	hd->scsi_scmd = SCMD_SELECT;
32841480Smckusick 	return (0);
32941480Smckusick }
33041480Smckusick 
33141480Smckusick static int
33241480Smckusick wait_for_select(hd)
33341480Smckusick 	volatile register struct scsidevice *hd;
33441480Smckusick {
33541480Smckusick 	u_char ints;
33641480Smckusick 
33741480Smckusick 	while ((ints = hd->scsi_ints) == 0)
33841480Smckusick 		DELAY(1);
33941480Smckusick 	hd->scsi_ints = ints;
34041480Smckusick 	return (!(hd->scsi_ssts & SSTS_INITIATOR));
34141480Smckusick }
34241480Smckusick 
34341480Smckusick static int
34441480Smckusick ixfer_start(hd, len, phase, wait)
34541480Smckusick 	volatile register struct scsidevice *hd;
34641480Smckusick 	int len;
34741480Smckusick 	u_char phase;
34841480Smckusick 	register int wait;
34941480Smckusick {
35041480Smckusick 
35141480Smckusick 	hd->scsi_tch = len >> 16;
35241480Smckusick 	hd->scsi_tcm = len >> 8;
35341480Smckusick 	hd->scsi_tcl = len;
35441480Smckusick 	hd->scsi_pctl = phase;
35541480Smckusick 	hd->scsi_tmod = 0; /*XXX*/
35641480Smckusick 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
35741480Smckusick 
35841480Smckusick 	/* wait for xfer to start or svc_req interrupt */
35941480Smckusick 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
36041480Smckusick 		if (hd->scsi_ints || --wait < 0) {
36141480Smckusick #ifdef DEBUG
36241480Smckusick 			if (scsi_debug)
36341480Smckusick 				printf("ixfer_start fail: i%x, w%d\n",
36441480Smckusick 				       hd->scsi_ints, wait);
36541480Smckusick #endif
36641480Smckusick 			HIST(ixstart_wait, wait)
36741480Smckusick 			return (0);
36841480Smckusick 		}
36941480Smckusick 		DELAY(1);
37041480Smckusick 	}
37141480Smckusick 	HIST(ixstart_wait, wait)
37241480Smckusick 	return (1);
37341480Smckusick }
37441480Smckusick 
37541480Smckusick static int
37641480Smckusick ixfer_out(hd, len, buf)
37741480Smckusick 	volatile register struct scsidevice *hd;
37841480Smckusick 	int len;
37941480Smckusick 	register u_char *buf;
38041480Smckusick {
38141480Smckusick 	register int wait = scsi_data_wait;
38241480Smckusick 
38341480Smckusick 	for (; len > 0; --len) {
38441480Smckusick 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
38541480Smckusick 			if (hd->scsi_ints || --wait < 0) {
38641480Smckusick #ifdef DEBUG
38741480Smckusick 				if (scsi_debug)
38841480Smckusick 					printf("ixfer_out fail: l%d i%x w%d\n",
38941480Smckusick 					       len, hd->scsi_ints, wait);
39041480Smckusick #endif
39141480Smckusick 				HIST(ixout_wait, wait)
39241480Smckusick 				return (len);
39341480Smckusick 			}
39441480Smckusick 			DELAY(1);
39541480Smckusick 		}
39641480Smckusick 		hd->scsi_dreg = *buf++;
39741480Smckusick 	}
39841480Smckusick 	HIST(ixout_wait, wait)
39941480Smckusick 	return (0);
40041480Smckusick }
40141480Smckusick 
40241480Smckusick static void
40341480Smckusick ixfer_in(hd, len, buf)
40441480Smckusick 	volatile register struct scsidevice *hd;
40541480Smckusick 	int len;
40641480Smckusick 	register u_char *buf;
40741480Smckusick {
40841480Smckusick 	register int wait = scsi_data_wait;
40941480Smckusick 
41041480Smckusick 	for (; len > 0; --len) {
41141480Smckusick 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
41241480Smckusick 			if (hd->scsi_ints || --wait < 0) {
41341480Smckusick 				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
41441480Smckusick 					*buf++ = hd->scsi_dreg;
41541480Smckusick 					--len;
41641480Smckusick 				}
41741480Smckusick #ifdef DEBUG
41841480Smckusick 				if (scsi_debug)
41941480Smckusick 					printf("ixfer_in fail: l%d i%x w%d\n",
42041480Smckusick 					       len, hd->scsi_ints, wait);
42141480Smckusick #endif
42241480Smckusick 				HIST(ixin_wait, wait)
42341480Smckusick 				return;
42441480Smckusick 			}
42541480Smckusick 			DELAY(1);
42641480Smckusick 		}
42741480Smckusick 		*buf++ = hd->scsi_dreg;
42841480Smckusick 	}
42941480Smckusick 	HIST(ixin_wait, wait)
43041480Smckusick }
43141480Smckusick 
43241480Smckusick static int
43341480Smckusick mxfer_in(hd, len, buf, phase)
43441480Smckusick 	volatile register struct scsidevice *hd;
43541480Smckusick 	register int len;
43641480Smckusick 	register u_char *buf;
43741480Smckusick 	register u_char phase;
43841480Smckusick {
43941480Smckusick 	register int wait = scsi_cmd_wait;
44041480Smckusick 	register int i;
44141480Smckusick 
44241480Smckusick 	hd->scsi_tmod = 0;
44341480Smckusick 	for (i = 0; i < len; ++i) {
44441480Smckusick 		/*
44541480Smckusick 		 * wait for the request line (which says the target
44641480Smckusick 		 * wants to give us data).  If the phase changes while
44741480Smckusick 		 * we're waiting, we're done.
44841480Smckusick 		 */
44941480Smckusick 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
45041480Smckusick 			if (--wait < 0) {
45141480Smckusick 				HIST(mxin_wait, wait)
45241480Smckusick 				return (-1);
45341480Smckusick 			}
45441480Smckusick 			if ((hd->scsi_psns & PHASE) != phase ||
45541480Smckusick 			    (hd->scsi_ssts & SSTS_INITIATOR) == 0)
45641480Smckusick 				goto out;
45741480Smckusick 
45841480Smckusick 			DELAY(1);
45941480Smckusick 		}
46041480Smckusick 		/*
46141480Smckusick 		 * set ack (which says we're ready for the data, wait for
46241480Smckusick 		 * req to go away (target says data is available), grab the
46341480Smckusick 		 * data, then reset ack (say we've got the data).
46441480Smckusick 		 */
46541480Smckusick 		hd->scsi_pctl = phase;
46641480Smckusick 		hd->scsi_scmd = SCMD_SET_ACK;
46741480Smckusick 		while (hd->scsi_psns & PSNS_REQ) {
46841480Smckusick 			if (--wait < 0) {
46941480Smckusick 				HIST(mxin_wait, wait)
47041480Smckusick 				return (-2);
47141480Smckusick 			}
47241480Smckusick 			DELAY(1);
47341480Smckusick 		}
47441480Smckusick 		*buf++ = hd->scsi_temp;
47541480Smckusick 		hd->scsi_scmd = SCMD_RST_ACK;
47641480Smckusick 		if (hd->scsi_psns & PSNS_ATN)
47741480Smckusick 			hd->scsi_scmd = SCMD_RST_ATN;
47841480Smckusick 	}
47941480Smckusick out:
48041480Smckusick 	HIST(mxin_wait, wait)
48141480Smckusick 	return (i);
48241480Smckusick }
48341480Smckusick 
48441480Smckusick /*
48541480Smckusick  * SCSI 'immediate' command:  issue a command to some SCSI device
48641480Smckusick  * and get back an 'immediate' response (i.e., do programmed xfer
48741480Smckusick  * to get the response data).  'cbuf' is a buffer containing a scsi
48841480Smckusick  * command of length clen bytes.  'buf' is a buffer of length 'len'
48941480Smckusick  * bytes for data.  The transfer direction is determined by the device
49041480Smckusick  * (i.e., by the scsi bus data xfer phase).  If 'len' is zero, the
49141480Smckusick  * command must supply no data.  'xferphase' is the bus phase the
49241480Smckusick  * caller expects to happen after the command is issued.  It should
49341480Smckusick  * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
49441480Smckusick  */
49541480Smckusick static int
49641480Smckusick scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
49741480Smckusick 	struct scsi_softc *hs;
49841480Smckusick 	int target;
49941480Smckusick 	u_char *cbuf;
50041480Smckusick 	int clen;
50141480Smckusick 	u_char *buf;
50241480Smckusick 	int len;
50341480Smckusick 	u_char xferphase;
50441480Smckusick {
50541480Smckusick 	volatile register struct scsidevice *hd =
50641480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
50741480Smckusick 	u_char phase, ints;
50841480Smckusick 	register int wait;
50941480Smckusick 
51041480Smckusick 	/* select the SCSI bus (it's an error if bus isn't free) */
51141480Smckusick 	if (issue_select(hd, target, hs->sc_scsi_addr))
51241480Smckusick 		return (-1);
51341480Smckusick 	if (wait_for_select(hd))
51441480Smckusick 		return (-1);
51541480Smckusick 	/*
51641480Smckusick 	 * Wait for a phase change (or error) then let the device
51741480Smckusick 	 * sequence us through the various SCSI phases.
51841480Smckusick 	 */
51941480Smckusick 	hs->sc_stat[0] = 0xff;
52041480Smckusick 	hs->sc_msg[0] = 0xff;
52141480Smckusick 	phase = CMD_PHASE;
52241480Smckusick 	while (1) {
52341480Smckusick 		wait = scsi_cmd_wait;
52441480Smckusick 		switch (phase) {
52541480Smckusick 
52641480Smckusick 		case CMD_PHASE:
52741480Smckusick 			if (ixfer_start(hd, clen, phase, wait))
52841480Smckusick 				if (ixfer_out(hd, clen, cbuf))
52941480Smckusick 					goto abort;
53041480Smckusick 			phase = xferphase;
53141480Smckusick 			break;
53241480Smckusick 
53341480Smckusick 		case DATA_IN_PHASE:
53441480Smckusick 			if (len <= 0)
53541480Smckusick 				goto abort;
53641480Smckusick 			wait = scsi_data_wait;
53741480Smckusick 			if (ixfer_start(hd, len, phase, wait) ||
53841480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
53941480Smckusick 				ixfer_in(hd, len, buf);
54041480Smckusick 			phase = STATUS_PHASE;
54141480Smckusick 			break;
54241480Smckusick 
54341480Smckusick 		case DATA_OUT_PHASE:
54441480Smckusick 			if (len <= 0)
54541480Smckusick 				goto abort;
54641480Smckusick 			wait = scsi_data_wait;
54741480Smckusick 			if (ixfer_start(hd, len, phase, wait)) {
54841480Smckusick 				if (ixfer_out(hd, len, buf))
54941480Smckusick 					goto abort;
55041480Smckusick 			}
55141480Smckusick 			phase = STATUS_PHASE;
55241480Smckusick 			break;
55341480Smckusick 
55441480Smckusick 		case STATUS_PHASE:
55541480Smckusick 			wait = scsi_data_wait;
55641480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
55741480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
55841480Smckusick 				ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat);
55941480Smckusick 			phase = MESG_IN_PHASE;
56041480Smckusick 			break;
56141480Smckusick 
56241480Smckusick 		case MESG_IN_PHASE:
56341480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
56441480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
56541480Smckusick 				ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
56641480Smckusick 				hd->scsi_scmd = SCMD_RST_ACK;
56741480Smckusick 			}
56841480Smckusick 			phase = BUS_FREE_PHASE;
56941480Smckusick 			break;
57041480Smckusick 
57141480Smckusick 		case BUS_FREE_PHASE:
57241480Smckusick 			goto out;
57341480Smckusick 
57441480Smckusick 		default:
57541480Smckusick 			printf("scsi%d: unexpected phase %d in icmd from %d\n",
57641480Smckusick 				hs->sc_hc->hp_unit, phase, target);
57741480Smckusick 			goto abort;
57841480Smckusick 		}
57941480Smckusick 		/* wait for last command to complete */
58041480Smckusick 		while ((ints = hd->scsi_ints) == 0) {
58141480Smckusick 			if (--wait < 0) {
58241480Smckusick 				HIST(cxin_wait, wait)
58341480Smckusick 				goto abort;
58441480Smckusick 			}
58541480Smckusick 			DELAY(1);
58641480Smckusick 		}
58741480Smckusick 		HIST(cxin_wait, wait)
58841480Smckusick 		hd->scsi_ints = ints;
58941480Smckusick 		if (ints & INTS_SRV_REQ)
59041480Smckusick 			phase = hd->scsi_psns & PHASE;
59141480Smckusick 		else if (ints & INTS_DISCON)
59241480Smckusick 			goto out;
59341480Smckusick 		else if ((ints & INTS_CMD_DONE) == 0) {
59441480Smckusick 			scsierror(hs, hd, ints);
59541480Smckusick 			goto abort;
59641480Smckusick 		}
59741480Smckusick 	}
59841480Smckusick abort:
59941480Smckusick 	scsiabort(hs, hd, "icmd");
60041480Smckusick out:
60141480Smckusick 	return (hs->sc_stat[0]);
60241480Smckusick }
60341480Smckusick 
60441480Smckusick /*
60541480Smckusick  * Finish SCSI xfer command:  After the completion interrupt from
60641480Smckusick  * a read/write operation, sequence through the final phases in
60741480Smckusick  * programmed i/o.  This routine is a lot like scsiicmd except we
60841480Smckusick  * skip (and don't allow) the select, cmd out and data in/out phases.
60941480Smckusick  */
61041480Smckusick static void
61141480Smckusick finishxfer(hs, hd, target)
61241480Smckusick 	struct scsi_softc *hs;
61341480Smckusick 	volatile register struct scsidevice *hd;
61441480Smckusick 	int target;
61541480Smckusick {
61641480Smckusick 	u_char phase, ints;
61741480Smckusick 
61841480Smckusick 	/*
61941480Smckusick 	 * We specified padding xfer so we ended with either a phase
62041480Smckusick 	 * change interrupt (normal case) or an error interrupt (handled
62141480Smckusick 	 * elsewhere).  Reset the board dma logic then try to get the
62241480Smckusick 	 * completion status & command done msg.  The reset confuses
62341480Smckusick 	 * the SPC REQ/ACK logic so we have to do any status/msg input
62441480Smckusick 	 * operations via 'manual xfer'.
62541480Smckusick 	 */
62641480Smckusick 	if (hd->scsi_ssts & SSTS_BUSY) {
62741480Smckusick 		int wait = scsi_cmd_wait;
62841480Smckusick 
62941480Smckusick 		/* wait for dma operation to finish */
63041480Smckusick 		while (hd->scsi_ssts & SSTS_BUSY) {
63141480Smckusick 			if (--wait < 0) {
63241480Smckusick #ifdef DEBUG
63341480Smckusick 				if (scsi_debug)
63441480Smckusick 					printf("finishxfer fail: ssts %x\n",
63541480Smckusick 					       hd->scsi_ssts);
63641480Smckusick #endif
63741480Smckusick 				HIST(fxfr_wait, wait)
63841480Smckusick 				goto abort;
63941480Smckusick 			}
64041480Smckusick 		}
64141480Smckusick 		HIST(fxfr_wait, wait)
64241480Smckusick 	}
64341480Smckusick 	hd->scsi_scmd |= SCMD_PROG_XFR;
64441480Smckusick 	hd->scsi_sctl |= SCTL_CTRLRST;
64541480Smckusick 	DELAY(1);
64641480Smckusick 	hd->scsi_sctl &=~ SCTL_CTRLRST;
64741480Smckusick 	hd->scsi_hconf = 0;
64841480Smckusick 	hs->sc_stat[0] = 0xff;
64941480Smckusick 	hs->sc_msg[0] = 0xff;
65041480Smckusick 	hd->scsi_csr = 0;
65141480Smckusick 	hd->scsi_ints = ints = hd->scsi_ints;
65241480Smckusick 	while (1) {
65341480Smckusick 		phase = hd->scsi_psns & PHASE;
65441480Smckusick 		switch (phase) {
65541480Smckusick 
65641480Smckusick 		case STATUS_PHASE:
65741480Smckusick 			if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat,
65841480Smckusick 				     phase) <= 0)
65941480Smckusick 				goto abort;
66041480Smckusick 			break;
66141480Smckusick 
66241480Smckusick 		case MESG_IN_PHASE:
66341480Smckusick 			if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg,
66441480Smckusick 				     phase) < 0)
66541480Smckusick 				goto abort;
66641480Smckusick 			break;
66741480Smckusick 
66841480Smckusick 		case BUS_FREE_PHASE:
66941480Smckusick 			return;
67041480Smckusick 
67141480Smckusick 		default:
67241480Smckusick 			printf("scsi%d: unexpected phase %d in finishxfer from %d\n",
67341480Smckusick 				hs->sc_hc->hp_unit, phase, target);
67441480Smckusick 			goto abort;
67541480Smckusick 		}
67641480Smckusick 		if (ints = hd->scsi_ints) {
67741480Smckusick 			hd->scsi_ints = ints;
67841480Smckusick 			if (ints & INTS_DISCON)
67941480Smckusick 				return;
68041480Smckusick 			else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) {
68141480Smckusick 				scsierror(hs, hd, ints);
68241480Smckusick 				break;
68341480Smckusick 			}
68441480Smckusick 		}
68541480Smckusick 		if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
68641480Smckusick 			return;
68741480Smckusick 	}
68841480Smckusick abort:
68941480Smckusick 	scsiabort(hs, hd, "finishxfer");
69041480Smckusick 	hs->sc_stat[0] = 0xfe;
69141480Smckusick }
69241480Smckusick 
69341480Smckusick int
69441480Smckusick scsi_test_unit_rdy(ctlr, slave, unit)
69541480Smckusick 	int ctlr, slave, unit;
69641480Smckusick {
69741480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
69841480Smckusick 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
69941480Smckusick 
70041480Smckusick 	cdb.lun = unit;
70141480Smckusick 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
70241480Smckusick 			 STATUS_PHASE));
70341480Smckusick }
70441480Smckusick 
70541480Smckusick int
70641480Smckusick scsi_request_sense(ctlr, slave, unit, buf, len)
70741480Smckusick 	int ctlr, slave, unit;
70841480Smckusick 	u_char *buf;
70941480Smckusick 	unsigned len;
71041480Smckusick {
71141480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
71241480Smckusick 	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
71341480Smckusick 
71441480Smckusick 	cdb.lun = unit;
71541480Smckusick 	cdb.len = len;
71641480Smckusick 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
71741480Smckusick }
71841480Smckusick 
71941480Smckusick int
72041480Smckusick scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
72141480Smckusick 	int ctlr, slave, unit;
72241480Smckusick 	struct scsi_fmt_cdb *cdb;
72341480Smckusick 	u_char *buf;
72441480Smckusick 	unsigned len;
72541480Smckusick {
72641480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
72741480Smckusick 
72841480Smckusick 	cdb->cdb[1] |= unit << 5;
72941480Smckusick 	return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len,
73041480Smckusick 			 rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));
73141480Smckusick }
73241480Smckusick 
73341480Smckusick /*
73441480Smckusick  * The following routines are test-and-transfer i/o versions of read/write
73541480Smckusick  * for things like reading disk labels and writing core dumps.  The
73641480Smckusick  * routine scsigo should be used for normal data transfers, NOT these
73741480Smckusick  * routines.
73841480Smckusick  */
73941480Smckusick int
74041480Smckusick scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift)
74141480Smckusick 	int ctlr, slave, unit;
74241480Smckusick 	u_char *buf;
74341480Smckusick 	u_int len;
74441480Smckusick 	daddr_t blk;
74541480Smckusick 	int bshift;
74641480Smckusick {
74741480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
74841480Smckusick 	struct scsi_cdb10 cdb;
74941480Smckusick 	int stat;
75041480Smckusick 	int old_wait = scsi_data_wait;
75141480Smckusick 
75241480Smckusick 	scsi_data_wait = 300000;
75341480Smckusick 	bzero(&cdb, sizeof(cdb));
75441480Smckusick 	cdb.cmd = CMD_READ_EXT;
75541480Smckusick 	cdb.lun = unit;
75641480Smckusick 	blk >>= bshift;
75741480Smckusick 	cdb.lbah = blk >> 24;
75841480Smckusick 	cdb.lbahm = blk >> 16;
75941480Smckusick 	cdb.lbalm = blk >> 8;
76041480Smckusick 	cdb.lbal = blk;
76141480Smckusick 	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
76241480Smckusick 	cdb.lenl = len >> (DEV_BSHIFT + bshift);
76341480Smckusick 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);
76441480Smckusick 	scsi_data_wait = old_wait;
76541480Smckusick 	return (stat);
76641480Smckusick }
76741480Smckusick 
76841480Smckusick int
76941480Smckusick scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift)
77041480Smckusick 	int ctlr, slave, unit;
77141480Smckusick 	u_char *buf;
77241480Smckusick 	u_int len;
77341480Smckusick 	daddr_t blk;
77441480Smckusick 	int bshift;
77541480Smckusick {
77641480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
77741480Smckusick 	struct scsi_cdb10 cdb;
77841480Smckusick 	int stat;
77941480Smckusick 	int old_wait = scsi_data_wait;
78041480Smckusick 
78141480Smckusick 	scsi_data_wait = 300000;
78241480Smckusick 
78341480Smckusick 	bzero(&cdb, sizeof(cdb));
78441480Smckusick 	cdb.cmd = CMD_WRITE_EXT;
78541480Smckusick 	cdb.lun = unit;
78641480Smckusick 	blk >>= bshift;
78741480Smckusick 	cdb.lbah = blk >> 24;
78841480Smckusick 	cdb.lbahm = blk >> 16;
78941480Smckusick 	cdb.lbalm = blk >> 8;
79041480Smckusick 	cdb.lbal = blk;
79141480Smckusick 	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
79241480Smckusick 	cdb.lenl = len >> (DEV_BSHIFT + bshift);
79341480Smckusick 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);
79441480Smckusick 	scsi_data_wait = old_wait;
79541480Smckusick 	return (stat);
79641480Smckusick }
79741480Smckusick 
79841480Smckusick int
79941480Smckusick scsireq(dq)
80041480Smckusick 	register struct devqueue *dq;
80141480Smckusick {
80241480Smckusick 	register struct devqueue *hq;
80341480Smckusick 
80441480Smckusick 	hq = &scsi_softc[dq->dq_ctlr].sc_sq;
80541480Smckusick 	insque(dq, hq->dq_back);
80641480Smckusick 	if (dq->dq_back == hq)
80741480Smckusick 		return(1);
80841480Smckusick 	return(0);
80941480Smckusick }
81041480Smckusick 
81141480Smckusick int
81241480Smckusick scsiustart(unit)
81341480Smckusick 	int unit;
81441480Smckusick {
81541480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
81641480Smckusick 
81741480Smckusick 	hs->sc_dq.dq_ctlr = DMA0 | DMA1;
81841480Smckusick 	if (dmareq(&hs->sc_dq))
81941480Smckusick 		return(1);
82041480Smckusick 	return(0);
82141480Smckusick }
82241480Smckusick 
82341480Smckusick void
82441480Smckusick scsistart(unit)
82541480Smckusick 	int unit;
82641480Smckusick {
82741480Smckusick 	register struct devqueue *dq;
82841480Smckusick 
82941480Smckusick 	dq = scsi_softc[unit].sc_sq.dq_forw;
83041480Smckusick 	(dq->dq_driver->d_go)(dq->dq_unit);
83141480Smckusick }
83241480Smckusick 
83341480Smckusick int
83441480Smckusick scsigo(ctlr, slave, unit, bp, cdb, pad)
83541480Smckusick 	int ctlr, slave, unit;
83641480Smckusick 	struct buf *bp;
83741480Smckusick 	struct scsi_fmt_cdb *cdb;
83841480Smckusick 	int pad;
83941480Smckusick {
84041480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
84141480Smckusick 	volatile register struct scsidevice *hd =
84241480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
84341480Smckusick 	int i, dmaflags;
84441480Smckusick 	u_char phase, ints, cmd;
84541480Smckusick 
84641480Smckusick 	cdb->cdb[1] |= unit << 5;
84741480Smckusick 
84841480Smckusick 	/* select the SCSI bus (it's an error if bus isn't free) */
84941480Smckusick 	if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) {
85041480Smckusick 		dmafree(&hs->sc_dq);
85141480Smckusick 		return (1);
85241480Smckusick 	}
85341480Smckusick 	/*
85441480Smckusick 	 * Wait for a phase change (or error) then let the device
85541480Smckusick 	 * sequence us through command phase (we may have to take
85641480Smckusick 	 * a msg in/out before doing the command).  If the disk has
85741480Smckusick 	 * to do a seek, it may be a long time until we get a change
85841480Smckusick 	 * to data phase so, in the absense of an explicit phase
85941480Smckusick 	 * change, we assume data phase will be coming up and tell
86041480Smckusick 	 * the SPC to start a transfer whenever it does.  We'll get
86141480Smckusick 	 * a service required interrupt later if this assumption is
86241480Smckusick 	 * wrong.  Otherwise we'll get a service required int when
86341480Smckusick 	 * the transfer changes to status phase.
86441480Smckusick 	 */
86541480Smckusick 	phase = CMD_PHASE;
86641480Smckusick 	while (1) {
86741480Smckusick 		register int wait = scsi_cmd_wait;
86841480Smckusick 
86941480Smckusick 		switch (phase) {
87041480Smckusick 
87141480Smckusick 		case CMD_PHASE:
87241480Smckusick 			if (ixfer_start(hd, cdb->len, phase, wait))
87341480Smckusick 				if (ixfer_out(hd, cdb->len, cdb->cdb))
87441480Smckusick 					goto abort;
87541480Smckusick 			break;
87641480Smckusick 
87741480Smckusick 		case MESG_IN_PHASE:
87841480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)||
87941480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
88041480Smckusick 				ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
88141480Smckusick 				hd->scsi_scmd = SCMD_RST_ACK;
88241480Smckusick 			}
88341480Smckusick 			phase = BUS_FREE_PHASE;
88441480Smckusick 			break;
88541480Smckusick 
88641480Smckusick 		case DATA_IN_PHASE:
88741480Smckusick 		case DATA_OUT_PHASE:
88841480Smckusick 			goto out;
88941480Smckusick 
89041480Smckusick 		default:
89141480Smckusick 			printf("scsi%d: unexpected phase %d in go from %d\n",
89241480Smckusick 				hs->sc_hc->hp_unit, phase, slave);
89341480Smckusick 			goto abort;
89441480Smckusick 		}
89541480Smckusick 		while ((ints = hd->scsi_ints) == 0) {
89641480Smckusick 			if (--wait < 0) {
89741480Smckusick 				HIST(sgo_wait, wait)
89841480Smckusick 				goto abort;
89941480Smckusick 			}
90041480Smckusick 			DELAY(1);
90141480Smckusick 		}
90241480Smckusick 		HIST(sgo_wait, wait)
90341480Smckusick 		hd->scsi_ints = ints;
90441480Smckusick 		if (ints & INTS_SRV_REQ)
90541480Smckusick 			phase = hd->scsi_psns & PHASE;
90641480Smckusick 		else if (ints & INTS_CMD_DONE)
90741480Smckusick 			goto out;
90841480Smckusick 		else {
90941480Smckusick 			scsierror(hs, hd, ints);
91041480Smckusick 			goto abort;
91141480Smckusick 		}
91241480Smckusick 	}
91341480Smckusick out:
91441480Smckusick 	/*
91541480Smckusick 	 * Reset the card dma logic, setup the dma channel then
91641480Smckusick 	 * get the dio part of the card set for a dma xfer.
91741480Smckusick 	 */
91841480Smckusick 	hd->scsi_hconf = 0;
91945514Smckusick 	cmd = CSR_IE;
92041480Smckusick 	dmaflags = DMAGO_NOINT;
92145514Smckusick 	if (scsi_pridma)
92245514Smckusick 		dmaflags |= DMAGO_PRI;
92341480Smckusick 	if (bp->b_flags & B_READ)
92441480Smckusick 		dmaflags |= DMAGO_READ;
92541480Smckusick 	if ((hs->sc_flags & SCSI_DMA32) &&
92641480Smckusick 	    ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) {
92741480Smckusick 		cmd |= CSR_DMA32;
92841480Smckusick 		dmaflags |= DMAGO_LWORD;
92941480Smckusick 	} else
93041480Smckusick 		dmaflags |= DMAGO_WORD;
93141480Smckusick 	dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags);
93241480Smckusick 
93341480Smckusick 	if (bp->b_flags & B_READ) {
93441480Smckusick 		cmd |= CSR_DMAIN;
93541480Smckusick 		phase = DATA_IN_PHASE;
93641480Smckusick 	} else
93741480Smckusick 		phase = DATA_OUT_PHASE;
93845514Smckusick 	/*
93945514Smckusick 	 * DMA enable bits must be set after size and direction bits.
94045514Smckusick 	 */
94141480Smckusick 	hd->scsi_csr = cmd;
94245514Smckusick 	hd->scsi_csr |= (CSR_DE0 << hs->sc_dq.dq_ctlr);
94341480Smckusick 	/*
94441480Smckusick 	 * Setup the SPC for the transfer.  We don't want to take
94541480Smckusick 	 * first a command complete then a service required interrupt
94641480Smckusick 	 * at the end of the transfer so we try to disable the cmd
94741480Smckusick 	 * complete by setting the transfer counter to more bytes
94841480Smckusick 	 * than we expect.  (XXX - This strategy may have to be
94941480Smckusick 	 * modified to deal with devices that return variable length
95041480Smckusick 	 * blocks, e.g., some tape drives.)
95141480Smckusick 	 */
95241480Smckusick 	cmd = SCMD_XFR;
95341480Smckusick 	i = (unsigned)bp->b_bcount;
95441480Smckusick 	if (pad) {
95541480Smckusick 		cmd |= SCMD_PAD;
95641480Smckusick 		/*
95741480Smckusick 		 * XXX - If we don't do this, the last 2 or 4 bytes
95841480Smckusick 		 * (depending on word/lword DMA) of a read get trashed.
95941480Smckusick 		 * It looks like it is necessary for the DMA to complete
96041480Smckusick 		 * before the SPC goes into "pad mode"???  Note: if we
96141480Smckusick 		 * also do this on a write, the request never completes.
96241480Smckusick 		 */
96341480Smckusick 		if (bp->b_flags & B_READ)
96441480Smckusick 			i += 2;
96541480Smckusick #ifdef DEBUG
96641480Smckusick 		hs->sc_flags |= SCSI_PAD;
96741480Smckusick 		if (i & 1)
96841480Smckusick 			printf("scsi%d: odd byte count: %d bytes @ %d\n",
96941480Smckusick 				ctlr, i, bp->b_cylin);
97041480Smckusick #endif
97141480Smckusick 	} else
97241480Smckusick 		i += 4;
97341480Smckusick 	hd->scsi_tch = i >> 16;
97441480Smckusick 	hd->scsi_tcm = i >> 8;
97541480Smckusick 	hd->scsi_tcl = i;
97641480Smckusick 	hd->scsi_pctl = phase;
97741480Smckusick 	hd->scsi_tmod = 0;
97841480Smckusick 	hd->scsi_scmd = cmd;
97941480Smckusick 	hs->sc_flags |= SCSI_IO;
98041480Smckusick 	return (0);
98141480Smckusick abort:
98241480Smckusick 	scsiabort(hs, hd, "go");
98341480Smckusick 	dmafree(&hs->sc_dq);
98441480Smckusick 	return (1);
98541480Smckusick }
98641480Smckusick 
98741480Smckusick void
98841480Smckusick scsidone(unit)
98941480Smckusick 	register int unit;
99041480Smckusick {
99141480Smckusick 	volatile register struct scsidevice *hd =
99241480Smckusick 			(struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr;
99341480Smckusick 
99445514Smckusick #ifdef DEBUG
99545514Smckusick 	if (scsi_debug)
99645514Smckusick 		printf("scsi%d: done called!\n");
99745514Smckusick #endif
99841480Smckusick 	/* dma operation is done -- turn off card dma */
99941480Smckusick 	hd->scsi_csr &=~ (CSR_DE1|CSR_DE0);
100041480Smckusick }
100141480Smckusick 
100241480Smckusick int
100341480Smckusick scsiintr(unit)
100441480Smckusick 	register int unit;
100541480Smckusick {
100641480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
100741480Smckusick 	volatile register struct scsidevice *hd =
100841480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
100941480Smckusick 	register u_char ints;
101041480Smckusick 	register struct devqueue *dq;
101141480Smckusick 
101241480Smckusick 	if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR))
101341480Smckusick 		return (0);
101441480Smckusick 
101541480Smckusick 	ints = hd->scsi_ints;
101641480Smckusick 	if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) {
101741480Smckusick 		/*
101841480Smckusick 		 * this should be the normal i/o completion case.
101941480Smckusick 		 * get the status & cmd complete msg then let the
102041480Smckusick 		 * device driver look at what happened.
102141480Smckusick 		 */
102241480Smckusick #ifdef DEBUG
102341480Smckusick 		int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) |
102441480Smckusick 			  hd->scsi_tcl;
102541480Smckusick 		if (!(hs->sc_flags & SCSI_PAD))
102641480Smckusick 			len -= 4;
102741480Smckusick 		hs->sc_flags &=~ SCSI_PAD;
102841480Smckusick #endif
102941480Smckusick 		dq = hs->sc_sq.dq_forw;
103041480Smckusick 		finishxfer(hs, hd, dq->dq_unit);
103141480Smckusick 		hs->sc_flags &=~ SCSI_IO;
103241480Smckusick 		dmafree(&hs->sc_dq);
103341480Smckusick 		(dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
103441480Smckusick 	} else {
103541480Smckusick 		/* Something unexpected happened -- deal with it. */
103641480Smckusick 		hd->scsi_ints = ints;
103741480Smckusick 		hd->scsi_csr = 0;
103841480Smckusick 		scsierror(hs, hd, ints);
103941480Smckusick 		scsiabort(hs, hd, "intr");
104041480Smckusick 		if (hs->sc_flags & SCSI_IO) {
104141480Smckusick 			hs->sc_flags &=~ SCSI_IO;
104241480Smckusick 			dmafree(&hs->sc_dq);
104341480Smckusick 			dq = hs->sc_sq.dq_forw;
104441480Smckusick 			(dq->dq_driver->d_intr)(dq->dq_unit, -1);
104541480Smckusick 		}
104641480Smckusick 	}
104741480Smckusick 	return(1);
104841480Smckusick }
104941480Smckusick 
105041480Smckusick void
105141480Smckusick scsifree(dq)
105241480Smckusick 	register struct devqueue *dq;
105341480Smckusick {
105441480Smckusick 	register struct devqueue *hq;
105541480Smckusick 
105641480Smckusick 	hq = &scsi_softc[dq->dq_ctlr].sc_sq;
105741480Smckusick 	remque(dq);
105841480Smckusick 	if ((dq = hq->dq_forw) != hq)
105941480Smckusick 		(dq->dq_driver->d_start)(dq->dq_unit);
106041480Smckusick }
106141480Smckusick #endif
1062