xref: /csrg-svn/sys/hp300/dev/scsi.c (revision 53930)
153019Smarc #ifndef DEBUG
253019Smarc #define DEBUG
353019Smarc #endif
441480Smckusick /*
541480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
641480Smckusick  * All rights reserved.
741480Smckusick  *
841480Smckusick  * This code is derived from software contributed to Berkeley by
941480Smckusick  * Van Jacobson of Lawrence Berkeley Laboratory.
1041480Smckusick  *
1141480Smckusick  * %sccs.include.redist.c%
1241480Smckusick  *
13*53930Shibler  *	@(#)scsi.c	7.7 (Berkeley) 06/05/92
1441480Smckusick  */
1541480Smckusick 
1641480Smckusick /*
1741480Smckusick  * HP9000/3xx 98658 SCSI host adaptor driver.
1841480Smckusick  */
1941480Smckusick #include "scsi.h"
2041480Smckusick #if NSCSI > 0
2141480Smckusick 
2241480Smckusick #ifndef lint
23*53930Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/scsi.c,v 1.2 92/04/10 20:48:29 mike Exp $";
2441480Smckusick #endif
2541480Smckusick 
2645788Sbostic #include "sys/param.h"
2745788Sbostic #include "sys/systm.h"
2845788Sbostic #include "sys/buf.h"
29*53930Shibler #include "hp/dev/device.h"
3045788Sbostic 
3141480Smckusick #include "scsivar.h"
3241480Smckusick #include "scsireg.h"
3341480Smckusick #include "dmavar.h"
3441480Smckusick 
3545788Sbostic #include "../include/cpu.h"
3645788Sbostic #include "../hp300/isr.h"
3741480Smckusick 
3846285Smckusick /*
3946285Smckusick  * SCSI delays
4046285Smckusick  * In u-seconds, primarily for state changes on the SPC.
4146285Smckusick  */
4246285Smckusick #define	SCSI_CMD_WAIT	1000	/* wait per step of 'immediate' cmds */
4346285Smckusick #define	SCSI_DATA_WAIT	1000	/* wait per data in/out step */
4446285Smckusick #define	SCSI_INIT_WAIT	50000	/* wait per step (both) during init */
4546285Smckusick 
4641480Smckusick extern void isrlink();
4741480Smckusick extern void _insque();
4841480Smckusick extern void _remque();
4941480Smckusick 
5041480Smckusick int	scsiinit(), scsigo(), scsiintr(), scsixfer();
5141480Smckusick void	scsistart(), scsidone(), scsifree(), scsireset();
5241480Smckusick struct	driver scsidriver = {
5341480Smckusick 	scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr,
5441480Smckusick 	(int (*)())scsidone,
5541480Smckusick };
5641480Smckusick 
5741480Smckusick struct	scsi_softc scsi_softc[NSCSI];
5841480Smckusick struct	isr scsi_isr[NSCSI];
5941480Smckusick 
6046285Smckusick int scsi_cmd_wait = SCSI_CMD_WAIT;
6146285Smckusick int scsi_data_wait = SCSI_DATA_WAIT;
6246285Smckusick int scsi_init_wait = SCSI_INIT_WAIT;
6346285Smckusick 
6441480Smckusick int scsi_nosync = 1;		/* inhibit sync xfers if 1 */
6545514Smckusick int scsi_pridma = 0;		/* use "priority" dma */
6641480Smckusick 
6741480Smckusick #ifdef DEBUG
6841480Smckusick int	scsi_debug = 0;
6941480Smckusick #define WAITHIST
7041480Smckusick #endif
7141480Smckusick 
7241480Smckusick #ifdef WAITHIST
7345514Smckusick #define MAXWAIT	1022
7441480Smckusick u_int	ixstart_wait[MAXWAIT+2];
7541480Smckusick u_int	ixin_wait[MAXWAIT+2];
7641480Smckusick u_int	ixout_wait[MAXWAIT+2];
7741480Smckusick u_int	mxin_wait[MAXWAIT+2];
7846285Smckusick u_int	mxin2_wait[MAXWAIT+2];
7941480Smckusick u_int	cxin_wait[MAXWAIT+2];
8041480Smckusick u_int	fxfr_wait[MAXWAIT+2];
8141480Smckusick u_int	sgo_wait[MAXWAIT+2];
8241480Smckusick #define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]);
8341480Smckusick #else
8441480Smckusick #define HIST(h,w)
8541480Smckusick #endif
8641480Smckusick 
8741480Smckusick #define	b_cylin		b_resid
8841480Smckusick 
8941480Smckusick static void
9041480Smckusick scsiabort(hs, hd, where)
9141480Smckusick 	register struct scsi_softc *hs;
9241480Smckusick 	volatile register struct scsidevice *hd;
9341480Smckusick 	char *where;
9441480Smckusick {
9541480Smckusick 	int len;
9653019Smarc 	int maxtries;	/* XXX - kludge till I understand whats *supposed* to happen */
9753019Smarc 	int startlen;	/* XXX - kludge till I understand whats *supposed* to happen */
9841480Smckusick 	u_char junk;
9941480Smckusick 
10041480Smckusick 	printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
10141480Smckusick 		hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts,
10241480Smckusick 		hd->scsi_ints);
10341480Smckusick 
10441480Smckusick 	hd->scsi_ints = hd->scsi_ints;
10541480Smckusick 	hd->scsi_csr = 0;
10641480Smckusick 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
10741480Smckusick 		/* no longer connected to scsi target */
10841480Smckusick 		return;
10941480Smckusick 
11041480Smckusick 	/* get the number of bytes remaining in current xfer + fudge */
11141480Smckusick 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
11241480Smckusick 
11341480Smckusick 	/* for that many bus cycles, try to send an abort msg */
11453019Smarc 	for (startlen = (len += 1024); (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
11541480Smckusick 		hd->scsi_scmd = SCMD_SET_ATN;
11653019Smarc 		maxtries = 1000;
11741480Smckusick 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
11841480Smckusick 			if (! (hd->scsi_ssts & SSTS_INITIATOR))
11941480Smckusick 				goto out;
12041480Smckusick 			DELAY(1);
12153019Smarc 			if (--maxtries == 0) {
12253019Smarc 				printf("-- scsiabort gave up after 1000 tries (startlen = %d len = %d)\n",
12353019Smarc 					startlen, len);
12453019Smarc 				goto out2;
12553019Smarc 			}
12653019Smarc 
12741480Smckusick 		}
12853019Smarc out2:
12941480Smckusick 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
13041480Smckusick 			hd->scsi_scmd = SCMD_RST_ATN;
13141480Smckusick 		hd->scsi_pctl = hd->scsi_psns & PHASE;
13241480Smckusick 		if (hd->scsi_psns & PHASE_IO) {
13341480Smckusick 			/* one of the input phases - read & discard a byte */
13441480Smckusick 			hd->scsi_scmd = SCMD_SET_ACK;
13541480Smckusick 			if (hd->scsi_tmod == 0)
13641480Smckusick 				while (hd->scsi_psns & PSNS_REQ)
13741480Smckusick 					DELAY(1);
13841480Smckusick 			junk = hd->scsi_temp;
13941480Smckusick 		} else {
14041480Smckusick 			/* one of the output phases - send an abort msg */
14141480Smckusick 			hd->scsi_temp = MSG_ABORT;
14241480Smckusick 			hd->scsi_scmd = SCMD_SET_ACK;
14341480Smckusick 			if (hd->scsi_tmod == 0)
14441480Smckusick 				while (hd->scsi_psns & PSNS_REQ)
14541480Smckusick 					DELAY(1);
14641480Smckusick 		}
14741480Smckusick 		hd->scsi_scmd = SCMD_RST_ACK;
14841480Smckusick 	}
14941480Smckusick out:
15041480Smckusick 	/*
15141480Smckusick 	 * Either the abort was successful & the bus is disconnected or
15241480Smckusick 	 * the device didn't listen.  If the latter, announce the problem.
15341480Smckusick 	 * Either way, reset the card & the SPC.
15441480Smckusick 	 */
15541480Smckusick 	if (len < 0 && hs)
15641480Smckusick 		printf("scsi%d: abort failed.  phase=0x%x, ssts=0x%x\n",
15741480Smckusick 			hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
15841480Smckusick 
15941480Smckusick 	if (! ((junk = hd->scsi_ints) & INTS_RESEL)) {
16041480Smckusick 		hd->scsi_sctl |= SCTL_CTRLRST;
16141480Smckusick 		DELAY(1);
16241480Smckusick 		hd->scsi_sctl &=~ SCTL_CTRLRST;
16341480Smckusick 		hd->scsi_hconf = 0;
16441480Smckusick 		hd->scsi_ints = hd->scsi_ints;
16541480Smckusick 	}
16641480Smckusick }
16741480Smckusick 
16846285Smckusick /*
16946285Smckusick  * XXX Set/reset long delays.
17046285Smckusick  *
17146285Smckusick  * if delay == 0, reset default delays
17246285Smckusick  * if delay < 0,  set both delays to default long initialization values
17346285Smckusick  * if delay > 0,  set both delays to this value
17446285Smckusick  *
17546285Smckusick  * Used when a devices is expected to respond slowly (e.g. during
17646285Smckusick  * initialization).
17746285Smckusick  */
17846285Smckusick void
17946285Smckusick scsi_delay(delay)
18046285Smckusick 	int delay;
18146285Smckusick {
18246285Smckusick 	static int saved_cmd_wait, saved_data_wait;
18346285Smckusick 
18446285Smckusick 	if (delay) {
18546285Smckusick 		saved_cmd_wait = scsi_cmd_wait;
18646285Smckusick 		saved_data_wait = scsi_data_wait;
18746285Smckusick 		if (delay > 0)
18846285Smckusick 			scsi_cmd_wait = scsi_data_wait = delay;
18946285Smckusick 		else
19046285Smckusick 			scsi_cmd_wait = scsi_data_wait = scsi_init_wait;
19146285Smckusick 	} else {
19246285Smckusick 		scsi_cmd_wait = saved_cmd_wait;
19346285Smckusick 		scsi_data_wait = saved_data_wait;
19446285Smckusick 	}
19546285Smckusick }
19646285Smckusick 
19741480Smckusick int
19841480Smckusick scsiinit(hc)
19941480Smckusick 	register struct hp_ctlr *hc;
20041480Smckusick {
20141480Smckusick 	register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
20241480Smckusick 	register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr;
20341480Smckusick 
20441480Smckusick 	if ((hd->scsi_id & ID_MASK) != SCSI_ID)
20541480Smckusick 		return(0);
20641480Smckusick 	hc->hp_ipl = SCSI_IPL(hd->scsi_csr);
20741480Smckusick 	hs->sc_hc = hc;
20841480Smckusick 	hs->sc_dq.dq_unit = hc->hp_unit;
20941480Smckusick 	hs->sc_dq.dq_driver = &scsidriver;
21041480Smckusick 	hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
21141480Smckusick 	scsi_isr[hc->hp_unit].isr_intr = scsiintr;
21241480Smckusick 	scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;
21341480Smckusick 	scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
21441480Smckusick 	isrlink(&scsi_isr[hc->hp_unit]);
21541480Smckusick 	scsireset(hc->hp_unit);
216*53930Shibler 	/*
217*53930Shibler 	 * XXX scale initialization wait according to CPU speed.
218*53930Shibler 	 * Should we do this for all wait?  Should we do this at all?
219*53930Shibler 	 */
220*53930Shibler 	scsi_init_wait *= cpuspeed;
22141480Smckusick 	return(1);
22241480Smckusick }
22341480Smckusick 
22441480Smckusick void
22541480Smckusick scsireset(unit)
22641480Smckusick 	register int unit;
22741480Smckusick {
22841480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
22941480Smckusick 	volatile register struct scsidevice *hd =
23041480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
23141480Smckusick 	u_int i;
23241480Smckusick 
23341480Smckusick 	if (hs->sc_flags & SCSI_ALIVE)
23441480Smckusick 		scsiabort(hs, hd, "reset");
23541480Smckusick 
23641480Smckusick 	printf("scsi%d: ", unit);
23741480Smckusick 
23841480Smckusick 	hd->scsi_id = 0xFF;
23941480Smckusick 	DELAY(100);
24041480Smckusick 	/*
24141480Smckusick 	 * Disable interrupts then reset the FUJI chip.
24241480Smckusick 	 */
24341480Smckusick 	hd->scsi_csr  = 0;
24441480Smckusick 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
24541480Smckusick 	hd->scsi_scmd = 0;
24641480Smckusick 	hd->scsi_tmod = 0;
24741480Smckusick 	hd->scsi_pctl = 0;
24841480Smckusick 	hd->scsi_temp = 0;
24941480Smckusick 	hd->scsi_tch  = 0;
25041480Smckusick 	hd->scsi_tcm  = 0;
25141480Smckusick 	hd->scsi_tcl  = 0;
25241480Smckusick 	hd->scsi_ints = 0;
25341480Smckusick 
25441480Smckusick 	if ((hd->scsi_id & ID_WORD_DMA) == 0) {
25541480Smckusick 		hs->sc_flags |= SCSI_DMA32;
25641480Smckusick 		printf("32 bit dma, ");
25741480Smckusick 	}
25841480Smckusick 
25941480Smckusick 	/* Determine Max Synchronous Transfer Rate */
26041480Smckusick 	if (scsi_nosync)
26141480Smckusick 		i = 3;
26241480Smckusick 	else
26341480Smckusick 		i = SCSI_SYNC_XFER(hd->scsi_hconf);
26441480Smckusick 	switch (i) {
26541480Smckusick 		case 0:
26641480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */
26741480Smckusick 			printf("250ns sync");
26841480Smckusick 			break;
26941480Smckusick 		case 1:
27041480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */
27141480Smckusick 			printf("375ns sync");
27241480Smckusick 			break;
27341480Smckusick 		case 2:
27441480Smckusick 			hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */
27541480Smckusick 			printf("500ns sync");
27641480Smckusick 			break;
27741480Smckusick 		case 3:
27841480Smckusick 			hs->sc_sync = 0;
27941480Smckusick 			printf("async");
28041480Smckusick 			break;
28141480Smckusick 		}
28241480Smckusick 
28341480Smckusick 	/*
28441480Smckusick 	 * Configure the FUJI chip with its SCSI address, all
28541480Smckusick 	 * interrupts enabled & appropriate parity.
28641480Smckusick 	 */
28741480Smckusick 	i = (~hd->scsi_hconf) & 0x7;
28841480Smckusick 	hs->sc_scsi_addr = 1 << i;
28941480Smckusick 	hd->scsi_bdid = i;
29041480Smckusick 	if (hd->scsi_hconf & HCONF_PARITY)
29141480Smckusick 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
29241480Smckusick 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
29341480Smckusick 				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
29441480Smckusick 	else {
29541480Smckusick 		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
29641480Smckusick 				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
29741480Smckusick 				SCTL_INTR_ENAB;
29841480Smckusick 		printf(", no parity");
29941480Smckusick 	}
30041480Smckusick 	hd->scsi_sctl &=~ SCTL_DISABLE;
30141480Smckusick 
30241480Smckusick 	printf(", scsi id %d\n", i);
30341480Smckusick 	hs->sc_flags |= SCSI_ALIVE;
30441480Smckusick }
30541480Smckusick 
30641480Smckusick static void
30741480Smckusick scsierror(hs, hd, ints)
30841480Smckusick 	register struct scsi_softc *hs;
30941480Smckusick 	volatile register struct scsidevice *hd;
31041480Smckusick 	u_char ints;
31141480Smckusick {
31241480Smckusick 	int unit = hs->sc_hc->hp_unit;
31341480Smckusick 	char *sep = "";
31441480Smckusick 
31541480Smckusick 	printf("scsi%d: ", unit);
31641480Smckusick 	if (ints & INTS_RST) {
31741480Smckusick 		DELAY(100);
31841480Smckusick 		if (hd->scsi_hconf & HCONF_SD)
31941480Smckusick 			printf("spurious RST interrupt");
32041480Smckusick 		else
32141480Smckusick 			printf("hardware error - check fuse");
32241480Smckusick 		sep = ", ";
32341480Smckusick 	}
32441480Smckusick 	if ((ints & INTS_HARD_ERR) || hd->scsi_serr) {
32541480Smckusick 		if (hd->scsi_serr & SERR_SCSI_PAR) {
32641480Smckusick 			printf("%sparity err", sep);
32741480Smckusick 			sep = ", ";
32841480Smckusick 		}
32941480Smckusick 		if (hd->scsi_serr & SERR_SPC_PAR) {
33041480Smckusick 			printf("%sSPC parity err", sep);
33141480Smckusick 			sep = ", ";
33241480Smckusick 		}
33341480Smckusick 		if (hd->scsi_serr & SERR_TC_PAR) {
33441480Smckusick 			printf("%sTC parity err", sep);
33541480Smckusick 			sep = ", ";
33641480Smckusick 		}
33741480Smckusick 		if (hd->scsi_serr & SERR_PHASE_ERR) {
33841480Smckusick 			printf("%sphase err", sep);
33941480Smckusick 			sep = ", ";
34041480Smckusick 		}
34141480Smckusick 		if (hd->scsi_serr & SERR_SHORT_XFR) {
34241480Smckusick 			printf("%ssync short transfer err", sep);
34341480Smckusick 			sep = ", ";
34441480Smckusick 		}
34541480Smckusick 		if (hd->scsi_serr & SERR_OFFSET) {
34641480Smckusick 			printf("%ssync offset error", sep);
34741480Smckusick 			sep = ", ";
34841480Smckusick 		}
34941480Smckusick 	}
35041480Smckusick 	if (ints & INTS_TIMEOUT)
35141480Smckusick 		printf("%sSPC select timeout error", sep);
35241480Smckusick 	if (ints & INTS_SRV_REQ)
35341480Smckusick 		printf("%sspurious SRV_REQ interrupt", sep);
35441480Smckusick 	if (ints & INTS_CMD_DONE)
35541480Smckusick 		printf("%sspurious CMD_DONE interrupt", sep);
35641480Smckusick 	if (ints & INTS_DISCON)
35741480Smckusick 		printf("%sspurious disconnect interrupt", sep);
35841480Smckusick 	if (ints & INTS_RESEL)
35941480Smckusick 		printf("%sspurious reselect interrupt", sep);
36041480Smckusick 	if (ints & INTS_SEL)
36141480Smckusick 		printf("%sspurious select interrupt", sep);
36241480Smckusick 	printf("\n");
36341480Smckusick }
36441480Smckusick 
36541480Smckusick static int
36641480Smckusick issue_select(hd, target, our_addr)
36741480Smckusick 	volatile register struct scsidevice *hd;
36841480Smckusick 	u_char target, our_addr;
36941480Smckusick {
37041480Smckusick 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
37141480Smckusick 		return (1);
37241480Smckusick 
37341480Smckusick 	if (hd->scsi_ints & INTS_DISCON)
37441480Smckusick 		hd->scsi_ints = INTS_DISCON;
37541480Smckusick 
37641480Smckusick 	hd->scsi_pctl = 0;
37741480Smckusick 	hd->scsi_temp = (1 << target) | our_addr;
37841480Smckusick 	/* select timeout is hardcoded to 2ms */
37941480Smckusick 	hd->scsi_tch = 0;
38041480Smckusick 	hd->scsi_tcm = 32;
38141480Smckusick 	hd->scsi_tcl = 4;
38241480Smckusick 
38341480Smckusick 	hd->scsi_scmd = SCMD_SELECT;
38441480Smckusick 	return (0);
38541480Smckusick }
38641480Smckusick 
38741480Smckusick static int
38841480Smckusick wait_for_select(hd)
38941480Smckusick 	volatile register struct scsidevice *hd;
39041480Smckusick {
39141480Smckusick 	u_char ints;
39241480Smckusick 
39341480Smckusick 	while ((ints = hd->scsi_ints) == 0)
39441480Smckusick 		DELAY(1);
39541480Smckusick 	hd->scsi_ints = ints;
39641480Smckusick 	return (!(hd->scsi_ssts & SSTS_INITIATOR));
39741480Smckusick }
39841480Smckusick 
39941480Smckusick static int
40041480Smckusick ixfer_start(hd, len, phase, wait)
40141480Smckusick 	volatile register struct scsidevice *hd;
40241480Smckusick 	int len;
40341480Smckusick 	u_char phase;
40441480Smckusick 	register int wait;
40541480Smckusick {
40641480Smckusick 
40741480Smckusick 	hd->scsi_tch = len >> 16;
40841480Smckusick 	hd->scsi_tcm = len >> 8;
40941480Smckusick 	hd->scsi_tcl = len;
41041480Smckusick 	hd->scsi_pctl = phase;
41141480Smckusick 	hd->scsi_tmod = 0; /*XXX*/
41241480Smckusick 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
41341480Smckusick 
41441480Smckusick 	/* wait for xfer to start or svc_req interrupt */
41541480Smckusick 	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
41641480Smckusick 		if (hd->scsi_ints || --wait < 0) {
41741480Smckusick #ifdef DEBUG
41841480Smckusick 			if (scsi_debug)
41941480Smckusick 				printf("ixfer_start fail: i%x, w%d\n",
42041480Smckusick 				       hd->scsi_ints, wait);
42141480Smckusick #endif
42241480Smckusick 			HIST(ixstart_wait, wait)
42341480Smckusick 			return (0);
42441480Smckusick 		}
42541480Smckusick 		DELAY(1);
42641480Smckusick 	}
42741480Smckusick 	HIST(ixstart_wait, wait)
42841480Smckusick 	return (1);
42941480Smckusick }
43041480Smckusick 
43141480Smckusick static int
43241480Smckusick ixfer_out(hd, len, buf)
43341480Smckusick 	volatile register struct scsidevice *hd;
43441480Smckusick 	int len;
43541480Smckusick 	register u_char *buf;
43641480Smckusick {
43741480Smckusick 	register int wait = scsi_data_wait;
43841480Smckusick 
43941480Smckusick 	for (; len > 0; --len) {
44041480Smckusick 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
44141480Smckusick 			if (hd->scsi_ints || --wait < 0) {
44241480Smckusick #ifdef DEBUG
44341480Smckusick 				if (scsi_debug)
44441480Smckusick 					printf("ixfer_out fail: l%d i%x w%d\n",
44541480Smckusick 					       len, hd->scsi_ints, wait);
44641480Smckusick #endif
44741480Smckusick 				HIST(ixout_wait, wait)
44841480Smckusick 				return (len);
44941480Smckusick 			}
45041480Smckusick 			DELAY(1);
45141480Smckusick 		}
45241480Smckusick 		hd->scsi_dreg = *buf++;
45341480Smckusick 	}
45441480Smckusick 	HIST(ixout_wait, wait)
45541480Smckusick 	return (0);
45641480Smckusick }
45741480Smckusick 
45841480Smckusick static void
45941480Smckusick ixfer_in(hd, len, buf)
46041480Smckusick 	volatile register struct scsidevice *hd;
46141480Smckusick 	int len;
46241480Smckusick 	register u_char *buf;
46341480Smckusick {
46441480Smckusick 	register int wait = scsi_data_wait;
46541480Smckusick 
46641480Smckusick 	for (; len > 0; --len) {
46741480Smckusick 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
46841480Smckusick 			if (hd->scsi_ints || --wait < 0) {
46941480Smckusick 				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
47041480Smckusick 					*buf++ = hd->scsi_dreg;
47141480Smckusick 					--len;
47241480Smckusick 				}
47341480Smckusick #ifdef DEBUG
47441480Smckusick 				if (scsi_debug)
47541480Smckusick 					printf("ixfer_in fail: l%d i%x w%d\n",
47641480Smckusick 					       len, hd->scsi_ints, wait);
47741480Smckusick #endif
47841480Smckusick 				HIST(ixin_wait, wait)
47941480Smckusick 				return;
48041480Smckusick 			}
48141480Smckusick 			DELAY(1);
48241480Smckusick 		}
48341480Smckusick 		*buf++ = hd->scsi_dreg;
48441480Smckusick 	}
48541480Smckusick 	HIST(ixin_wait, wait)
48641480Smckusick }
48741480Smckusick 
48841480Smckusick static int
48941480Smckusick mxfer_in(hd, len, buf, phase)
49041480Smckusick 	volatile register struct scsidevice *hd;
49141480Smckusick 	register int len;
49241480Smckusick 	register u_char *buf;
49341480Smckusick 	register u_char phase;
49441480Smckusick {
49541480Smckusick 	register int wait = scsi_cmd_wait;
49641480Smckusick 	register int i;
49741480Smckusick 
49841480Smckusick 	hd->scsi_tmod = 0;
49941480Smckusick 	for (i = 0; i < len; ++i) {
50041480Smckusick 		/*
50146285Smckusick 		 * manual sez: reset ATN before ACK is sent.
50246285Smckusick 		 */
50346285Smckusick 		if (hd->scsi_psns & PSNS_ATN)
50446285Smckusick 			hd->scsi_scmd = SCMD_RST_ATN;
50546285Smckusick 		/*
50641480Smckusick 		 * wait for the request line (which says the target
50741480Smckusick 		 * wants to give us data).  If the phase changes while
50841480Smckusick 		 * we're waiting, we're done.
50941480Smckusick 		 */
51041480Smckusick 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
51141480Smckusick 			if (--wait < 0) {
51241480Smckusick 				HIST(mxin_wait, wait)
51341480Smckusick 				return (-1);
51441480Smckusick 			}
51541480Smckusick 			if ((hd->scsi_psns & PHASE) != phase ||
51641480Smckusick 			    (hd->scsi_ssts & SSTS_INITIATOR) == 0)
51741480Smckusick 				goto out;
51841480Smckusick 
51941480Smckusick 			DELAY(1);
52041480Smckusick 		}
52141480Smckusick 		/*
52241480Smckusick 		 * set ack (which says we're ready for the data, wait for
52341480Smckusick 		 * req to go away (target says data is available), grab the
52441480Smckusick 		 * data, then reset ack (say we've got the data).
52541480Smckusick 		 */
52641480Smckusick 		hd->scsi_pctl = phase;
52741480Smckusick 		hd->scsi_scmd = SCMD_SET_ACK;
52841480Smckusick 		while (hd->scsi_psns & PSNS_REQ) {
52941480Smckusick 			if (--wait < 0) {
53041480Smckusick 				HIST(mxin_wait, wait)
53141480Smckusick 				return (-2);
53241480Smckusick 			}
53341480Smckusick 			DELAY(1);
53441480Smckusick 		}
53541480Smckusick 		*buf++ = hd->scsi_temp;
53641480Smckusick 		hd->scsi_scmd = SCMD_RST_ACK;
53741480Smckusick 	}
53841480Smckusick out:
53941480Smckusick 	HIST(mxin_wait, wait)
54046285Smckusick 	/*
54146285Smckusick 	 * Wait for manual transfer to finish.
54246285Smckusick 	 * Avoids occasional "unexpected phase" errors in finishxfer
54346285Smckusick 	 * formerly addressed by per-slave delays.
54446285Smckusick 	 */
54546285Smckusick 	wait = scsi_cmd_wait;
54646285Smckusick 	while ((hd->scsi_ssts & SSTS_ACTIVE) == SSTS_INITIATOR) {
54746285Smckusick 		if (--wait < 0)
54846285Smckusick 			break;
54946285Smckusick 		DELAY(1);
55046285Smckusick 	}
55146285Smckusick 	HIST(mxin2_wait, wait)
55241480Smckusick 	return (i);
55341480Smckusick }
55441480Smckusick 
55541480Smckusick /*
55641480Smckusick  * SCSI 'immediate' command:  issue a command to some SCSI device
55741480Smckusick  * and get back an 'immediate' response (i.e., do programmed xfer
55841480Smckusick  * to get the response data).  'cbuf' is a buffer containing a scsi
55941480Smckusick  * command of length clen bytes.  'buf' is a buffer of length 'len'
56041480Smckusick  * bytes for data.  The transfer direction is determined by the device
56141480Smckusick  * (i.e., by the scsi bus data xfer phase).  If 'len' is zero, the
56241480Smckusick  * command must supply no data.  'xferphase' is the bus phase the
56341480Smckusick  * caller expects to happen after the command is issued.  It should
56441480Smckusick  * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
56541480Smckusick  */
56641480Smckusick static int
56741480Smckusick scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
56841480Smckusick 	struct scsi_softc *hs;
56941480Smckusick 	int target;
57041480Smckusick 	u_char *cbuf;
57141480Smckusick 	int clen;
57241480Smckusick 	u_char *buf;
57341480Smckusick 	int len;
57441480Smckusick 	u_char xferphase;
57541480Smckusick {
57641480Smckusick 	volatile register struct scsidevice *hd =
57741480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
57841480Smckusick 	u_char phase, ints;
57941480Smckusick 	register int wait;
58041480Smckusick 
58141480Smckusick 	/* select the SCSI bus (it's an error if bus isn't free) */
58241480Smckusick 	if (issue_select(hd, target, hs->sc_scsi_addr))
58341480Smckusick 		return (-1);
58441480Smckusick 	if (wait_for_select(hd))
58541480Smckusick 		return (-1);
58641480Smckusick 	/*
58741480Smckusick 	 * Wait for a phase change (or error) then let the device
58841480Smckusick 	 * sequence us through the various SCSI phases.
58941480Smckusick 	 */
59041480Smckusick 	hs->sc_stat[0] = 0xff;
59141480Smckusick 	hs->sc_msg[0] = 0xff;
59241480Smckusick 	phase = CMD_PHASE;
59341480Smckusick 	while (1) {
59441480Smckusick 		wait = scsi_cmd_wait;
59541480Smckusick 		switch (phase) {
59641480Smckusick 
59741480Smckusick 		case CMD_PHASE:
59841480Smckusick 			if (ixfer_start(hd, clen, phase, wait))
59941480Smckusick 				if (ixfer_out(hd, clen, cbuf))
60041480Smckusick 					goto abort;
60141480Smckusick 			phase = xferphase;
60241480Smckusick 			break;
60341480Smckusick 
60441480Smckusick 		case DATA_IN_PHASE:
60541480Smckusick 			if (len <= 0)
60641480Smckusick 				goto abort;
60741480Smckusick 			wait = scsi_data_wait;
60841480Smckusick 			if (ixfer_start(hd, len, phase, wait) ||
60941480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
61041480Smckusick 				ixfer_in(hd, len, buf);
61141480Smckusick 			phase = STATUS_PHASE;
61241480Smckusick 			break;
61341480Smckusick 
61441480Smckusick 		case DATA_OUT_PHASE:
61541480Smckusick 			if (len <= 0)
61641480Smckusick 				goto abort;
61741480Smckusick 			wait = scsi_data_wait;
61841480Smckusick 			if (ixfer_start(hd, len, phase, wait)) {
61941480Smckusick 				if (ixfer_out(hd, len, buf))
62041480Smckusick 					goto abort;
62141480Smckusick 			}
62241480Smckusick 			phase = STATUS_PHASE;
62341480Smckusick 			break;
62441480Smckusick 
62541480Smckusick 		case STATUS_PHASE:
62641480Smckusick 			wait = scsi_data_wait;
62741480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
62841480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))
62941480Smckusick 				ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat);
63041480Smckusick 			phase = MESG_IN_PHASE;
63141480Smckusick 			break;
63241480Smckusick 
63341480Smckusick 		case MESG_IN_PHASE:
63441480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
63541480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
63641480Smckusick 				ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
63741480Smckusick 				hd->scsi_scmd = SCMD_RST_ACK;
63841480Smckusick 			}
63941480Smckusick 			phase = BUS_FREE_PHASE;
64041480Smckusick 			break;
64141480Smckusick 
64241480Smckusick 		case BUS_FREE_PHASE:
64341480Smckusick 			goto out;
64441480Smckusick 
64541480Smckusick 		default:
64641480Smckusick 			printf("scsi%d: unexpected phase %d in icmd from %d\n",
64741480Smckusick 				hs->sc_hc->hp_unit, phase, target);
64841480Smckusick 			goto abort;
64941480Smckusick 		}
65041480Smckusick 		/* wait for last command to complete */
65141480Smckusick 		while ((ints = hd->scsi_ints) == 0) {
65241480Smckusick 			if (--wait < 0) {
65341480Smckusick 				HIST(cxin_wait, wait)
65441480Smckusick 				goto abort;
65541480Smckusick 			}
65641480Smckusick 			DELAY(1);
65741480Smckusick 		}
65841480Smckusick 		HIST(cxin_wait, wait)
65941480Smckusick 		hd->scsi_ints = ints;
66041480Smckusick 		if (ints & INTS_SRV_REQ)
66141480Smckusick 			phase = hd->scsi_psns & PHASE;
66241480Smckusick 		else if (ints & INTS_DISCON)
66341480Smckusick 			goto out;
66441480Smckusick 		else if ((ints & INTS_CMD_DONE) == 0) {
66541480Smckusick 			scsierror(hs, hd, ints);
66641480Smckusick 			goto abort;
66741480Smckusick 		}
66841480Smckusick 	}
66941480Smckusick abort:
67041480Smckusick 	scsiabort(hs, hd, "icmd");
67141480Smckusick out:
67241480Smckusick 	return (hs->sc_stat[0]);
67341480Smckusick }
67441480Smckusick 
67541480Smckusick /*
67641480Smckusick  * Finish SCSI xfer command:  After the completion interrupt from
67741480Smckusick  * a read/write operation, sequence through the final phases in
67841480Smckusick  * programmed i/o.  This routine is a lot like scsiicmd except we
67941480Smckusick  * skip (and don't allow) the select, cmd out and data in/out phases.
68041480Smckusick  */
68141480Smckusick static void
68241480Smckusick finishxfer(hs, hd, target)
68341480Smckusick 	struct scsi_softc *hs;
68441480Smckusick 	volatile register struct scsidevice *hd;
68541480Smckusick 	int target;
68641480Smckusick {
68741480Smckusick 	u_char phase, ints;
68841480Smckusick 
68941480Smckusick 	/*
69041480Smckusick 	 * We specified padding xfer so we ended with either a phase
69141480Smckusick 	 * change interrupt (normal case) or an error interrupt (handled
69241480Smckusick 	 * elsewhere).  Reset the board dma logic then try to get the
69341480Smckusick 	 * completion status & command done msg.  The reset confuses
69441480Smckusick 	 * the SPC REQ/ACK logic so we have to do any status/msg input
69541480Smckusick 	 * operations via 'manual xfer'.
69641480Smckusick 	 */
69741480Smckusick 	if (hd->scsi_ssts & SSTS_BUSY) {
69841480Smckusick 		int wait = scsi_cmd_wait;
69941480Smckusick 
70041480Smckusick 		/* wait for dma operation to finish */
70141480Smckusick 		while (hd->scsi_ssts & SSTS_BUSY) {
70241480Smckusick 			if (--wait < 0) {
70341480Smckusick #ifdef DEBUG
70441480Smckusick 				if (scsi_debug)
70541480Smckusick 					printf("finishxfer fail: ssts %x\n",
70641480Smckusick 					       hd->scsi_ssts);
70741480Smckusick #endif
70841480Smckusick 				HIST(fxfr_wait, wait)
70941480Smckusick 				goto abort;
71041480Smckusick 			}
71141480Smckusick 		}
71241480Smckusick 		HIST(fxfr_wait, wait)
71341480Smckusick 	}
71441480Smckusick 	hd->scsi_scmd |= SCMD_PROG_XFR;
71541480Smckusick 	hd->scsi_sctl |= SCTL_CTRLRST;
71641480Smckusick 	DELAY(1);
71741480Smckusick 	hd->scsi_sctl &=~ SCTL_CTRLRST;
71841480Smckusick 	hd->scsi_hconf = 0;
71953019Smarc 	/*
72053019Smarc 	 * The following delay is definitely needed when trying to
72153019Smarc 	 * write on a write protected disk (in the optical jukebox anyways),
72253019Smarc 	 * but we shall see if other unexplained machine freezeups
72353019Smarc 	 * also stop occuring...  A value of 5 seems to work but
72453019Smarc 	 * 10 seems safer considering the potential consequences.
72553019Smarc 	 */
72653019Smarc 	DELAY(10);
72741480Smckusick 	hs->sc_stat[0] = 0xff;
72841480Smckusick 	hs->sc_msg[0] = 0xff;
72941480Smckusick 	hd->scsi_csr = 0;
73041480Smckusick 	hd->scsi_ints = ints = hd->scsi_ints;
73141480Smckusick 	while (1) {
73241480Smckusick 		phase = hd->scsi_psns & PHASE;
73341480Smckusick 		switch (phase) {
73441480Smckusick 
73541480Smckusick 		case STATUS_PHASE:
73641480Smckusick 			if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat,
73741480Smckusick 				     phase) <= 0)
73841480Smckusick 				goto abort;
73941480Smckusick 			break;
74041480Smckusick 
74141480Smckusick 		case MESG_IN_PHASE:
74241480Smckusick 			if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg,
74341480Smckusick 				     phase) < 0)
74441480Smckusick 				goto abort;
74541480Smckusick 			break;
74641480Smckusick 
74741480Smckusick 		case BUS_FREE_PHASE:
74841480Smckusick 			return;
74941480Smckusick 
75041480Smckusick 		default:
75141480Smckusick 			printf("scsi%d: unexpected phase %d in finishxfer from %d\n",
75241480Smckusick 				hs->sc_hc->hp_unit, phase, target);
75341480Smckusick 			goto abort;
75441480Smckusick 		}
75541480Smckusick 		if (ints = hd->scsi_ints) {
75641480Smckusick 			hd->scsi_ints = ints;
75741480Smckusick 			if (ints & INTS_DISCON)
75841480Smckusick 				return;
75941480Smckusick 			else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) {
76041480Smckusick 				scsierror(hs, hd, ints);
76141480Smckusick 				break;
76241480Smckusick 			}
76341480Smckusick 		}
76441480Smckusick 		if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
76541480Smckusick 			return;
76641480Smckusick 	}
76741480Smckusick abort:
76841480Smckusick 	scsiabort(hs, hd, "finishxfer");
76941480Smckusick 	hs->sc_stat[0] = 0xfe;
77041480Smckusick }
77141480Smckusick 
77241480Smckusick int
77341480Smckusick scsi_test_unit_rdy(ctlr, slave, unit)
77441480Smckusick 	int ctlr, slave, unit;
77541480Smckusick {
77641480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
77741480Smckusick 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
77841480Smckusick 
77941480Smckusick 	cdb.lun = unit;
78041480Smckusick 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
78141480Smckusick 			 STATUS_PHASE));
78241480Smckusick }
78341480Smckusick 
78441480Smckusick int
78541480Smckusick scsi_request_sense(ctlr, slave, unit, buf, len)
78641480Smckusick 	int ctlr, slave, unit;
78741480Smckusick 	u_char *buf;
78841480Smckusick 	unsigned len;
78941480Smckusick {
79041480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
79141480Smckusick 	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
79241480Smckusick 
79341480Smckusick 	cdb.lun = unit;
79441480Smckusick 	cdb.len = len;
79541480Smckusick 	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
79641480Smckusick }
79741480Smckusick 
79841480Smckusick int
79941480Smckusick scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
80041480Smckusick 	int ctlr, slave, unit;
80141480Smckusick 	struct scsi_fmt_cdb *cdb;
80241480Smckusick 	u_char *buf;
80341480Smckusick 	unsigned len;
80441480Smckusick {
80541480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
80641480Smckusick 
80741480Smckusick 	cdb->cdb[1] |= unit << 5;
80841480Smckusick 	return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len,
80941480Smckusick 			 rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));
81041480Smckusick }
81141480Smckusick 
81241480Smckusick /*
81341480Smckusick  * The following routines are test-and-transfer i/o versions of read/write
81441480Smckusick  * for things like reading disk labels and writing core dumps.  The
81541480Smckusick  * routine scsigo should be used for normal data transfers, NOT these
81641480Smckusick  * routines.
81741480Smckusick  */
81841480Smckusick int
81941480Smckusick scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift)
82041480Smckusick 	int ctlr, slave, unit;
82141480Smckusick 	u_char *buf;
82241480Smckusick 	u_int len;
82341480Smckusick 	daddr_t blk;
82441480Smckusick 	int bshift;
82541480Smckusick {
82641480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
82741480Smckusick 	struct scsi_cdb10 cdb;
82841480Smckusick 	int stat;
82941480Smckusick 	int old_wait = scsi_data_wait;
83041480Smckusick 
83141480Smckusick 	scsi_data_wait = 300000;
83241480Smckusick 	bzero(&cdb, sizeof(cdb));
83341480Smckusick 	cdb.cmd = CMD_READ_EXT;
83441480Smckusick 	cdb.lun = unit;
83541480Smckusick 	blk >>= bshift;
83641480Smckusick 	cdb.lbah = blk >> 24;
83741480Smckusick 	cdb.lbahm = blk >> 16;
83841480Smckusick 	cdb.lbalm = blk >> 8;
83941480Smckusick 	cdb.lbal = blk;
84041480Smckusick 	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
84141480Smckusick 	cdb.lenl = len >> (DEV_BSHIFT + bshift);
84241480Smckusick 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);
84341480Smckusick 	scsi_data_wait = old_wait;
84441480Smckusick 	return (stat);
84541480Smckusick }
84641480Smckusick 
84741480Smckusick int
84841480Smckusick scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift)
84941480Smckusick 	int ctlr, slave, unit;
85041480Smckusick 	u_char *buf;
85141480Smckusick 	u_int len;
85241480Smckusick 	daddr_t blk;
85341480Smckusick 	int bshift;
85441480Smckusick {
85541480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
85641480Smckusick 	struct scsi_cdb10 cdb;
85741480Smckusick 	int stat;
85841480Smckusick 	int old_wait = scsi_data_wait;
85941480Smckusick 
86041480Smckusick 	scsi_data_wait = 300000;
86141480Smckusick 
86241480Smckusick 	bzero(&cdb, sizeof(cdb));
86341480Smckusick 	cdb.cmd = CMD_WRITE_EXT;
86441480Smckusick 	cdb.lun = unit;
86541480Smckusick 	blk >>= bshift;
86641480Smckusick 	cdb.lbah = blk >> 24;
86741480Smckusick 	cdb.lbahm = blk >> 16;
86841480Smckusick 	cdb.lbalm = blk >> 8;
86941480Smckusick 	cdb.lbal = blk;
87041480Smckusick 	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
87141480Smckusick 	cdb.lenl = len >> (DEV_BSHIFT + bshift);
87241480Smckusick 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);
87341480Smckusick 	scsi_data_wait = old_wait;
87441480Smckusick 	return (stat);
87541480Smckusick }
87641480Smckusick 
87741480Smckusick int
87841480Smckusick scsireq(dq)
87941480Smckusick 	register struct devqueue *dq;
88041480Smckusick {
88141480Smckusick 	register struct devqueue *hq;
88241480Smckusick 
88341480Smckusick 	hq = &scsi_softc[dq->dq_ctlr].sc_sq;
88441480Smckusick 	insque(dq, hq->dq_back);
88541480Smckusick 	if (dq->dq_back == hq)
88641480Smckusick 		return(1);
88741480Smckusick 	return(0);
88841480Smckusick }
88941480Smckusick 
89041480Smckusick int
89141480Smckusick scsiustart(unit)
89241480Smckusick 	int unit;
89341480Smckusick {
89441480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
89541480Smckusick 
89641480Smckusick 	hs->sc_dq.dq_ctlr = DMA0 | DMA1;
897*53930Shibler 	hs->sc_flags |= SCSI_HAVEDMA;
89841480Smckusick 	if (dmareq(&hs->sc_dq))
89941480Smckusick 		return(1);
90041480Smckusick 	return(0);
90141480Smckusick }
90241480Smckusick 
90341480Smckusick void
90441480Smckusick scsistart(unit)
90541480Smckusick 	int unit;
90641480Smckusick {
90741480Smckusick 	register struct devqueue *dq;
90841480Smckusick 
90941480Smckusick 	dq = scsi_softc[unit].sc_sq.dq_forw;
91041480Smckusick 	(dq->dq_driver->d_go)(dq->dq_unit);
91141480Smckusick }
91241480Smckusick 
91341480Smckusick int
91441480Smckusick scsigo(ctlr, slave, unit, bp, cdb, pad)
91541480Smckusick 	int ctlr, slave, unit;
91641480Smckusick 	struct buf *bp;
91741480Smckusick 	struct scsi_fmt_cdb *cdb;
91841480Smckusick 	int pad;
91941480Smckusick {
92041480Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
92141480Smckusick 	volatile register struct scsidevice *hd =
92241480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
92341480Smckusick 	int i, dmaflags;
92441480Smckusick 	u_char phase, ints, cmd;
92541480Smckusick 
92641480Smckusick 	cdb->cdb[1] |= unit << 5;
92741480Smckusick 
92841480Smckusick 	/* select the SCSI bus (it's an error if bus isn't free) */
92941480Smckusick 	if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) {
930*53930Shibler 		if (hs->sc_flags & SCSI_HAVEDMA) {
931*53930Shibler 			hs->sc_flags &=~ SCSI_HAVEDMA;
932*53930Shibler 			dmafree(&hs->sc_dq);
933*53930Shibler 		}
93441480Smckusick 		return (1);
93541480Smckusick 	}
93641480Smckusick 	/*
93741480Smckusick 	 * Wait for a phase change (or error) then let the device
93841480Smckusick 	 * sequence us through command phase (we may have to take
93941480Smckusick 	 * a msg in/out before doing the command).  If the disk has
94041480Smckusick 	 * to do a seek, it may be a long time until we get a change
94141480Smckusick 	 * to data phase so, in the absense of an explicit phase
94241480Smckusick 	 * change, we assume data phase will be coming up and tell
94341480Smckusick 	 * the SPC to start a transfer whenever it does.  We'll get
94441480Smckusick 	 * a service required interrupt later if this assumption is
94541480Smckusick 	 * wrong.  Otherwise we'll get a service required int when
94641480Smckusick 	 * the transfer changes to status phase.
94741480Smckusick 	 */
94841480Smckusick 	phase = CMD_PHASE;
94941480Smckusick 	while (1) {
95041480Smckusick 		register int wait = scsi_cmd_wait;
95141480Smckusick 
95241480Smckusick 		switch (phase) {
95341480Smckusick 
95441480Smckusick 		case CMD_PHASE:
95541480Smckusick 			if (ixfer_start(hd, cdb->len, phase, wait))
95641480Smckusick 				if (ixfer_out(hd, cdb->len, cdb->cdb))
95741480Smckusick 					goto abort;
95841480Smckusick 			break;
95941480Smckusick 
96041480Smckusick 		case MESG_IN_PHASE:
96141480Smckusick 			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)||
96241480Smckusick 			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
96341480Smckusick 				ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
96441480Smckusick 				hd->scsi_scmd = SCMD_RST_ACK;
96541480Smckusick 			}
96641480Smckusick 			phase = BUS_FREE_PHASE;
96741480Smckusick 			break;
96841480Smckusick 
96941480Smckusick 		case DATA_IN_PHASE:
97041480Smckusick 		case DATA_OUT_PHASE:
97141480Smckusick 			goto out;
97241480Smckusick 
97341480Smckusick 		default:
97441480Smckusick 			printf("scsi%d: unexpected phase %d in go from %d\n",
97541480Smckusick 				hs->sc_hc->hp_unit, phase, slave);
97641480Smckusick 			goto abort;
97741480Smckusick 		}
97841480Smckusick 		while ((ints = hd->scsi_ints) == 0) {
97941480Smckusick 			if (--wait < 0) {
98041480Smckusick 				HIST(sgo_wait, wait)
98141480Smckusick 				goto abort;
98241480Smckusick 			}
98341480Smckusick 			DELAY(1);
98441480Smckusick 		}
98541480Smckusick 		HIST(sgo_wait, wait)
98641480Smckusick 		hd->scsi_ints = ints;
98741480Smckusick 		if (ints & INTS_SRV_REQ)
98841480Smckusick 			phase = hd->scsi_psns & PHASE;
98941480Smckusick 		else if (ints & INTS_CMD_DONE)
99041480Smckusick 			goto out;
99141480Smckusick 		else {
99241480Smckusick 			scsierror(hs, hd, ints);
99341480Smckusick 			goto abort;
99441480Smckusick 		}
99541480Smckusick 	}
99641480Smckusick out:
99741480Smckusick 	/*
99841480Smckusick 	 * Reset the card dma logic, setup the dma channel then
99941480Smckusick 	 * get the dio part of the card set for a dma xfer.
100041480Smckusick 	 */
100141480Smckusick 	hd->scsi_hconf = 0;
100245514Smckusick 	cmd = CSR_IE;
100341480Smckusick 	dmaflags = DMAGO_NOINT;
100445514Smckusick 	if (scsi_pridma)
100545514Smckusick 		dmaflags |= DMAGO_PRI;
100641480Smckusick 	if (bp->b_flags & B_READ)
100741480Smckusick 		dmaflags |= DMAGO_READ;
100841480Smckusick 	if ((hs->sc_flags & SCSI_DMA32) &&
100941480Smckusick 	    ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) {
101041480Smckusick 		cmd |= CSR_DMA32;
101141480Smckusick 		dmaflags |= DMAGO_LWORD;
101241480Smckusick 	} else
101341480Smckusick 		dmaflags |= DMAGO_WORD;
101441480Smckusick 	dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags);
101541480Smckusick 
101641480Smckusick 	if (bp->b_flags & B_READ) {
101741480Smckusick 		cmd |= CSR_DMAIN;
101841480Smckusick 		phase = DATA_IN_PHASE;
101941480Smckusick 	} else
102041480Smckusick 		phase = DATA_OUT_PHASE;
102145514Smckusick 	/*
102245514Smckusick 	 * DMA enable bits must be set after size and direction bits.
102345514Smckusick 	 */
102441480Smckusick 	hd->scsi_csr = cmd;
102545514Smckusick 	hd->scsi_csr |= (CSR_DE0 << hs->sc_dq.dq_ctlr);
102641480Smckusick 	/*
102741480Smckusick 	 * Setup the SPC for the transfer.  We don't want to take
102841480Smckusick 	 * first a command complete then a service required interrupt
102941480Smckusick 	 * at the end of the transfer so we try to disable the cmd
103041480Smckusick 	 * complete by setting the transfer counter to more bytes
103141480Smckusick 	 * than we expect.  (XXX - This strategy may have to be
103241480Smckusick 	 * modified to deal with devices that return variable length
103341480Smckusick 	 * blocks, e.g., some tape drives.)
103441480Smckusick 	 */
103541480Smckusick 	cmd = SCMD_XFR;
103641480Smckusick 	i = (unsigned)bp->b_bcount;
103741480Smckusick 	if (pad) {
103841480Smckusick 		cmd |= SCMD_PAD;
103941480Smckusick 		/*
104041480Smckusick 		 * XXX - If we don't do this, the last 2 or 4 bytes
104141480Smckusick 		 * (depending on word/lword DMA) of a read get trashed.
104241480Smckusick 		 * It looks like it is necessary for the DMA to complete
104341480Smckusick 		 * before the SPC goes into "pad mode"???  Note: if we
104441480Smckusick 		 * also do this on a write, the request never completes.
104541480Smckusick 		 */
104641480Smckusick 		if (bp->b_flags & B_READ)
104741480Smckusick 			i += 2;
104841480Smckusick #ifdef DEBUG
104941480Smckusick 		hs->sc_flags |= SCSI_PAD;
105041480Smckusick 		if (i & 1)
105141480Smckusick 			printf("scsi%d: odd byte count: %d bytes @ %d\n",
105241480Smckusick 				ctlr, i, bp->b_cylin);
105341480Smckusick #endif
105441480Smckusick 	} else
105541480Smckusick 		i += 4;
105641480Smckusick 	hd->scsi_tch = i >> 16;
105741480Smckusick 	hd->scsi_tcm = i >> 8;
105841480Smckusick 	hd->scsi_tcl = i;
105941480Smckusick 	hd->scsi_pctl = phase;
106041480Smckusick 	hd->scsi_tmod = 0;
106141480Smckusick 	hd->scsi_scmd = cmd;
106241480Smckusick 	hs->sc_flags |= SCSI_IO;
106341480Smckusick 	return (0);
106441480Smckusick abort:
106541480Smckusick 	scsiabort(hs, hd, "go");
1066*53930Shibler 	hs->sc_flags &=~ SCSI_HAVEDMA;
106741480Smckusick 	dmafree(&hs->sc_dq);
106841480Smckusick 	return (1);
106941480Smckusick }
107041480Smckusick 
107141480Smckusick void
107241480Smckusick scsidone(unit)
107341480Smckusick 	register int unit;
107441480Smckusick {
107541480Smckusick 	volatile register struct scsidevice *hd =
107641480Smckusick 			(struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr;
107741480Smckusick 
107845514Smckusick #ifdef DEBUG
107945514Smckusick 	if (scsi_debug)
108045514Smckusick 		printf("scsi%d: done called!\n");
108145514Smckusick #endif
108241480Smckusick 	/* dma operation is done -- turn off card dma */
108341480Smckusick 	hd->scsi_csr &=~ (CSR_DE1|CSR_DE0);
108441480Smckusick }
108541480Smckusick 
108641480Smckusick int
108741480Smckusick scsiintr(unit)
108841480Smckusick 	register int unit;
108941480Smckusick {
109041480Smckusick 	register struct scsi_softc *hs = &scsi_softc[unit];
109141480Smckusick 	volatile register struct scsidevice *hd =
109241480Smckusick 				(struct scsidevice *)hs->sc_hc->hp_addr;
109341480Smckusick 	register u_char ints;
109441480Smckusick 	register struct devqueue *dq;
109541480Smckusick 
109641480Smckusick 	if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR))
109741480Smckusick 		return (0);
109841480Smckusick 
109941480Smckusick 	ints = hd->scsi_ints;
110041480Smckusick 	if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) {
110141480Smckusick 		/*
110241480Smckusick 		 * this should be the normal i/o completion case.
110341480Smckusick 		 * get the status & cmd complete msg then let the
110441480Smckusick 		 * device driver look at what happened.
110541480Smckusick 		 */
110641480Smckusick #ifdef DEBUG
110741480Smckusick 		int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) |
110841480Smckusick 			  hd->scsi_tcl;
110941480Smckusick 		if (!(hs->sc_flags & SCSI_PAD))
111041480Smckusick 			len -= 4;
111141480Smckusick 		hs->sc_flags &=~ SCSI_PAD;
111241480Smckusick #endif
111341480Smckusick 		dq = hs->sc_sq.dq_forw;
111446285Smckusick 		finishxfer(hs, hd, dq->dq_slave);
1115*53930Shibler 		hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);
111641480Smckusick 		dmafree(&hs->sc_dq);
111741480Smckusick 		(dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
111841480Smckusick 	} else {
111941480Smckusick 		/* Something unexpected happened -- deal with it. */
112041480Smckusick 		hd->scsi_ints = ints;
112141480Smckusick 		hd->scsi_csr = 0;
112241480Smckusick 		scsierror(hs, hd, ints);
112341480Smckusick 		scsiabort(hs, hd, "intr");
112441480Smckusick 		if (hs->sc_flags & SCSI_IO) {
1125*53930Shibler 			hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);
112641480Smckusick 			dmafree(&hs->sc_dq);
112741480Smckusick 			dq = hs->sc_sq.dq_forw;
112841480Smckusick 			(dq->dq_driver->d_intr)(dq->dq_unit, -1);
112941480Smckusick 		}
113041480Smckusick 	}
113141480Smckusick 	return(1);
113241480Smckusick }
113341480Smckusick 
113441480Smckusick void
113541480Smckusick scsifree(dq)
113641480Smckusick 	register struct devqueue *dq;
113741480Smckusick {
113841480Smckusick 	register struct devqueue *hq;
113941480Smckusick 
114041480Smckusick 	hq = &scsi_softc[dq->dq_ctlr].sc_sq;
114141480Smckusick 	remque(dq);
114241480Smckusick 	if ((dq = hq->dq_forw) != hq)
114341480Smckusick 		(dq->dq_driver->d_start)(dq->dq_unit);
114441480Smckusick }
114546285Smckusick 
114646285Smckusick /*
114746285Smckusick  * (XXX) The following routine is needed for the SCSI tape driver
114846285Smckusick  * to read odd-size records.
114946285Smckusick  */
115046285Smckusick 
115146285Smckusick #include "st.h"
115246285Smckusick #if NST > 0
115346285Smckusick int
115446285Smckusick scsi_tt_oddio(ctlr, slave, unit, buf, len, b_flags, freedma)
115546285Smckusick 	int ctlr, slave, unit, b_flags;
115646285Smckusick 	u_char *buf;
115746285Smckusick 	u_int len;
115846285Smckusick {
115946285Smckusick 	register struct scsi_softc *hs = &scsi_softc[ctlr];
116046285Smckusick 	struct scsi_cdb6 cdb;
116146285Smckusick 	u_char iphase;
116246285Smckusick 	int stat;
116346285Smckusick 
1164*53930Shibler #ifdef DEBUG
1165*53930Shibler 	if (freedma && (hs->sc_flags & SCSI_HAVEDMA) == 0 ||
1166*53930Shibler 	    !freedma && (hs->sc_flags & SCSI_HAVEDMA))
1167*53930Shibler 		printf("oddio: freedma (%d) inconsistency (flags=%x)\n",
1168*53930Shibler 		       freedma, hs->sc_flags);
1169*53930Shibler #endif
117046285Smckusick 	/*
117146285Smckusick 	 * First free any DMA channel that was allocated.
117246285Smckusick 	 * We can't use DMA to do this transfer.
117346285Smckusick 	 */
1174*53930Shibler 	if (freedma) {
1175*53930Shibler 		hs->sc_flags &=~ SCSI_HAVEDMA;
117646285Smckusick 		dmafree(hs->sc_dq);
1177*53930Shibler 	}
117846285Smckusick 	/*
117946285Smckusick 	 * Initialize command block
118046285Smckusick 	 */
118146285Smckusick 	bzero(&cdb, sizeof(cdb));
118246285Smckusick 	cdb.lun = unit;
118346285Smckusick 	cdb.lbam = (len >> 16) & 0xff;
118446285Smckusick 	cdb.lbal = (len >> 8) & 0xff;
118546285Smckusick 	cdb.len = len & 0xff;
118646285Smckusick 	if (buf == 0) {
118746285Smckusick 		cdb.cmd = CMD_SPACE;
118846285Smckusick 		cdb.lun |= 0x00;
118946285Smckusick 		len = 0;
119046285Smckusick 		iphase = MESG_IN_PHASE;
119146285Smckusick 	} else if (b_flags & B_READ) {
119246285Smckusick 		cdb.cmd = CMD_READ;
119346285Smckusick 		iphase = DATA_IN_PHASE;
119446285Smckusick 	} else {
119546285Smckusick 		cdb.cmd = CMD_WRITE;
119646285Smckusick 		iphase = DATA_OUT_PHASE;
119746285Smckusick 	}
119846285Smckusick 	/*
119946285Smckusick 	 * Perform command (with very long delays)
120046285Smckusick 	 */
120146285Smckusick 	scsi_delay(30000000);
120246285Smckusick 	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, iphase);
120346285Smckusick 	scsi_delay(0);
120446285Smckusick 	return (stat);
120546285Smckusick }
120641480Smckusick #endif
120746285Smckusick #endif
1208