xref: /csrg-svn/sys/pmax/dev/asc.c (revision 56819)
152889Sbostic /*-
252889Sbostic  * Copyright (c) 1992 The Regents of the University of California.
352889Sbostic  * All rights reserved.
452889Sbostic  *
552889Sbostic  * This code is derived from software contributed to Berkeley by
6*56819Sralph  * Ralph Campbell and Rick Macklem.
752889Sbostic  *
852889Sbostic  * %sccs.include.redist.c%
952889Sbostic  *
10*56819Sralph  *	@(#)asc.c	7.8 (Berkeley) 11/15/92
1152889Sbostic  */
1252889Sbostic 
1352889Sbostic /*
1452889Sbostic  * Mach Operating System
1552889Sbostic  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
1652889Sbostic  * All Rights Reserved.
1752889Sbostic  *
1852889Sbostic  * Permission to use, copy, modify and distribute this software and its
1952889Sbostic  * documentation is hereby granted, provided that both the copyright
2052889Sbostic  * notice and this permission notice appear in all copies of the
2152889Sbostic  * software, derivative works or modified versions, and any portions
2252889Sbostic  * thereof, and that both notices appear in supporting documentation.
2352889Sbostic  *
2452889Sbostic  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
2552889Sbostic  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
2652889Sbostic  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2752889Sbostic  *
2852889Sbostic  * Carnegie Mellon requests users of this software to return to
2952889Sbostic  *
3052889Sbostic  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
3152889Sbostic  *  School of Computer Science
3252889Sbostic  *  Carnegie Mellon University
3352889Sbostic  *  Pittsburgh PA 15213-3890
3452889Sbostic  *
3552889Sbostic  * any improvements or extensions that they make and grant Carnegie the
3652889Sbostic  * rights to redistribute these changes.
3752889Sbostic  */
3852889Sbostic 
3952889Sbostic /*
4052889Sbostic  * HISTORY
4152889Sbostic  * $Log:	scsi_53C94_hdw.c,v $
4252889Sbostic  * Revision 2.5  91/02/05  17:45:07  mrt
4352889Sbostic  * 	Added author notices
4452889Sbostic  * 	[91/02/04  11:18:43  mrt]
4552889Sbostic  *
4652889Sbostic  * 	Changed to use new Mach copyright
4752889Sbostic  * 	[91/02/02  12:17:20  mrt]
4852889Sbostic  *
4952889Sbostic  * Revision 2.4  91/01/08  15:48:24  rpd
5052889Sbostic  * 	Added continuation argument to thread_block.
5152889Sbostic  * 	[90/12/27            rpd]
5252889Sbostic  *
5352889Sbostic  * Revision 2.3  90/12/05  23:34:48  af
5452889Sbostic  * 	Recovered from pmax merge.. and from the destruction of a disk.
5552889Sbostic  * 	[90/12/03  23:40:40  af]
5652889Sbostic  *
5752889Sbostic  * Revision 2.1.1.1  90/11/01  03:39:09  af
5852889Sbostic  * 	Created, from the DEC specs:
5952889Sbostic  * 	"PMAZ-AA TURBOchannel SCSI Module Functional Specification"
6052889Sbostic  * 	Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
6152889Sbostic  * 	And from the NCR data sheets
6252889Sbostic  * 	"NCR 53C94, 53C95, 53C96 Advances SCSI Controller"
6352889Sbostic  * 	[90/09/03            af]
6452889Sbostic  */
6552889Sbostic 
6652889Sbostic /*
6752889Sbostic  *	File: scsi_53C94_hdw.h
6852889Sbostic  * 	Author: Alessandro Forin, Carnegie Mellon University
6952889Sbostic  *	Date:	9/90
7052889Sbostic  *
7152889Sbostic  *	Bottom layer of the SCSI driver: chip-dependent functions
7252889Sbostic  *
7352889Sbostic  *	This file contains the code that is specific to the NCR 53C94
7452889Sbostic  *	SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
7552889Sbostic  *	operation, and interrupt routine.
7652889Sbostic  */
7752889Sbostic 
7852889Sbostic /*
7952889Sbostic  * This layer works based on small simple 'scripts' that are installed
8052889Sbostic  * at the start of the command and drive the chip to completion.
8152889Sbostic  * The idea comes from the specs of the NCR 53C700 'script' processor.
8252889Sbostic  *
8352889Sbostic  * There are various reasons for this, mainly
8452889Sbostic  * - Performance: identify the common (successful) path, and follow it;
8552889Sbostic  *   at interrupt time no code is needed to find the current status
8652889Sbostic  * - Code size: it should be easy to compact common operations
8752889Sbostic  * - Adaptability: the code skeleton should adapt to different chips without
8852889Sbostic  *   terrible complications.
8952889Sbostic  * - Error handling: and it is easy to modify the actions performed
9052889Sbostic  *   by the scripts to cope with strange but well identified sequences
9152889Sbostic  *
9252889Sbostic  */
9352889Sbostic 
94*56819Sralph #include <asc.h>
9552889Sbostic #if NASC > 0
9652889Sbostic 
9756522Sbostic #include <sys/param.h>
9856522Sbostic #include <sys/systm.h>
99*56819Sralph #include <sys/dkstat.h>
100*56819Sralph #include <sys/buf.h>
101*56819Sralph #include <sys/conf.h>
10256522Sbostic #include <sys/errno.h>
10352889Sbostic 
104*56819Sralph #include <machine/machConst.h>
105*56819Sralph 
10656525Sbostic #include <pmax/dev/device.h>
10756525Sbostic #include <pmax/dev/scsi.h>
10856525Sbostic #include <pmax/dev/ascreg.h>
10952889Sbostic 
110*56819Sralph #include <pmax/pmax/asic.h>
111*56819Sralph #include <pmax/pmax/kmin.h>
112*56819Sralph #include <pmax/pmax/pmaxtype.h>
113*56819Sralph 
11452889Sbostic #define ASC_OFFSET_53C94	0x0		/* from module base */
11552889Sbostic #define ASC_OFFSET_DMAR		0x40000		/* DMA Address Register */
11652889Sbostic #define ASC_OFFSET_RAM		0x80000		/* SRAM Buffer */
11752889Sbostic #define ASC_OFFSET_ROM		0xc0000		/* Diagnostic ROM */
11852889Sbostic 
11952889Sbostic #define	ASC_RAM_SIZE		0x20000		/* 128k (32k*32) */
12052889Sbostic 
121*56819Sralph #define	readback(a)	{ register int foo; foo = (a); }
12252889Sbostic /*
12352889Sbostic  * DMA Address Register
12452889Sbostic  */
12552889Sbostic #define ASC_DMAR_MASK		0x1ffff		/* 17 bits, 128k */
12652889Sbostic #define ASC_DMAR_WRITE		0x80000000	/* DMA direction bit */
12753080Sralph #define	ASC_DMA_ADDR(x)		((unsigned)(x) & ASC_DMAR_MASK)
12852889Sbostic 
12952889Sbostic /*
13052889Sbostic  * Synch xfer parameters, and timing conversions
13152889Sbostic  */
132*56819Sralph #define SCSI_MIN_PERIOD		50	/* in 4 nsecs units */
133*56819Sralph #define ASC_MIN_PERIOD25	5	/* in CLKS/BYTE, 1 CLK = 40nsecs */
134*56819Sralph #define ASC_MIN_PERIOD12	3	/* in CLKS/BYTE, 1 CLK = 80nsecs */
135*56819Sralph #define ASC_MAX_PERIOD25	35	/* in CLKS/BYTE, 1 CLK = 40nsecs */
136*56819Sralph #define ASC_MAX_PERIOD12	18	/* in CLKS/BYTE, 1 CLK = 80nsecs */
137*56819Sralph #define ASC_MAX_OFFSET		15	/* pure number */
13852889Sbostic 
139*56819Sralph extern int pmax_boardtype;
140*56819Sralph 
141*56819Sralph /*
142*56819Sralph  * In 4ns ticks.
143*56819Sralph  */
14452889Sbostic int	asc_to_scsi_period[] = {
145*56819Sralph 	32,
146*56819Sralph 	33,
147*56819Sralph 	34,
148*56819Sralph 	35,
149*56819Sralph 	5,
150*56819Sralph 	5,
151*56819Sralph 	6,
152*56819Sralph 	7,
153*56819Sralph 	8,
154*56819Sralph 	9,
155*56819Sralph 	10,
156*56819Sralph 	11,
157*56819Sralph 	12,
158*56819Sralph 	13,
159*56819Sralph 	14,
160*56819Sralph 	15,
161*56819Sralph 	16,
162*56819Sralph 	17,
163*56819Sralph 	18,
164*56819Sralph 	19,
165*56819Sralph 	20,
166*56819Sralph 	21,
167*56819Sralph 	22,
168*56819Sralph 	23,
169*56819Sralph 	24,
170*56819Sralph 	25,
171*56819Sralph 	26,
172*56819Sralph 	27,
173*56819Sralph 	28,
174*56819Sralph 	29,
175*56819Sralph 	30,
176*56819Sralph 	31,
17752889Sbostic };
17852889Sbostic 
17952889Sbostic /*
18052889Sbostic  * Internal forward declarations.
18152889Sbostic  */
18252889Sbostic static void asc_reset();
18352889Sbostic static void asc_startcmd();
18452889Sbostic 
18552889Sbostic #ifdef DEBUG
18652889Sbostic int	asc_debug = 1;
18752889Sbostic int	asc_debug_cmd;
18852889Sbostic int	asc_debug_bn;
18952889Sbostic int	asc_debug_sz;
19052889Sbostic #define NLOG 16
19152889Sbostic struct asc_log {
19252889Sbostic 	u_int	status;
19352889Sbostic 	u_char	state;
19452889Sbostic 	u_char	msg;
19552889Sbostic 	int	target;
19652889Sbostic } asc_log[NLOG], *asc_logp = asc_log;
19752889Sbostic #define PACK(unit, status, ss, ir) \
19852889Sbostic 	((unit << 24) | (status << 16) | (ss << 8) | ir)
19952889Sbostic #endif
20052889Sbostic 
20152889Sbostic /*
20252889Sbostic  * Scripts are entries in a state machine table.
20352889Sbostic  * A script has four parts: a pre-condition, an action, a command to the chip,
20452889Sbostic  * and an index into asc_scripts for the next state. The first triggers error
20552889Sbostic  * handling if not satisfied and in our case it is formed by the
20652889Sbostic  * values of the interrupt register and status register, this
20752889Sbostic  * basically captures the phase of the bus and the TC and BS
20852889Sbostic  * bits.  The action part is just a function pointer, and the
20952889Sbostic  * command is what the 53C94 should be told to do at the end
21052889Sbostic  * of the action processing.  This command is only issued and the
21152889Sbostic  * script proceeds if the action routine returns TRUE.
21252889Sbostic  * See asc_intr() for how and where this is all done.
21352889Sbostic  */
21452889Sbostic typedef struct script {
21552889Sbostic 	int		condition;	/* expected state at interrupt time */
21652889Sbostic 	int		(*action)();	/* extra operations */
21752889Sbostic 	int		command;	/* command to the chip */
21852889Sbostic 	struct script	*next;		/* index into asc_scripts for next state */
21952889Sbostic } script_t;
22052889Sbostic 
22152889Sbostic /* Matching on the condition value */
22252889Sbostic #define	SCRIPT_MATCH(ir, csr)		((ir) | (ASC_PHASE(csr) << 8))
22352889Sbostic 
22452889Sbostic /* forward decls of script actions */
225*56819Sralph static int script_nop();		/* when nothing needed */
226*56819Sralph static int asc_end();			/* all come to an end */
227*56819Sralph static int asc_get_status();		/* get status from target */
228*56819Sralph static int asc_dma_in();		/* start reading data from target */
229*56819Sralph static int asc_last_dma_in();		/* cleanup after all data is read */
230*56819Sralph static int asc_resume_in();		/* resume data in after a message */
231*56819Sralph static int asc_resume_dma_in();		/* resume DMA after a disconnect */
232*56819Sralph static int asc_dma_out();		/* send data to target via dma */
233*56819Sralph static int asc_last_dma_out();		/* cleanup after all data is written */
234*56819Sralph static int asc_resume_out();		/* resume data out after a message */
235*56819Sralph static int asc_resume_dma_out();	/* resume DMA after a disconnect */
236*56819Sralph static int asc_sendsync();		/* negotiate sync xfer */
237*56819Sralph static int asc_replysync();		/* negotiate sync xfer */
238*56819Sralph static int asc_msg_in();		/* process a message byte */
239*56819Sralph static int asc_disconnect();		/* process an expected disconnect */
24052889Sbostic 
24152889Sbostic /* Define the index into asc_scripts for various state transitions */
24252889Sbostic #define	SCRIPT_DATA_IN		0
24352942Sralph #define	SCRIPT_CONTINUE_IN	2
24452942Sralph #define	SCRIPT_DATA_OUT		3
24552942Sralph #define	SCRIPT_CONTINUE_OUT	5
24652942Sralph #define	SCRIPT_SIMPLE		6
24752942Sralph #define	SCRIPT_GET_STATUS	7
24852942Sralph #define	SCRIPT_MSG_IN		9
24952942Sralph #define	SCRIPT_REPLY_SYNC	11
25052889Sbostic #define	SCRIPT_TRY_SYNC		12
25152942Sralph #define	SCRIPT_DISCONNECT	15
25252942Sralph #define	SCRIPT_RESEL		16
25352942Sralph #define	SCRIPT_RESUME_IN	17
25452942Sralph #define	SCRIPT_RESUME_DMA_IN	18
25552942Sralph #define	SCRIPT_RESUME_OUT	19
25652942Sralph #define	SCRIPT_RESUME_DMA_OUT	20
25752942Sralph #define	SCRIPT_RESUME_NO_DATA	21
25852889Sbostic 
25952889Sbostic /*
26052889Sbostic  * Scripts
26152889Sbostic  */
26252889Sbostic script_t asc_scripts[] = {
26352942Sralph 	/* start data in */
26452889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
26552889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
26652942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
26752889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
26852889Sbostic 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
26952942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
27052889Sbostic 
27152942Sralph 	/* continue data in after a chuck is finished */
27252942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/*  2 */
27352942Sralph 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
27452942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
27552942Sralph 
27652942Sralph 	/* start data out */
27752942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  3 */
27852889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
27952942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
28052942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  4 */
28152889Sbostic 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
28252942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
28352889Sbostic 
28452942Sralph 	/* continue data out after a chuck is finished */
28552942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/*  5 */
28652942Sralph 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
28752942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
28852942Sralph 
28952889Sbostic 	/* simple command with no data transfer */
29052942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  6 */
29152889Sbostic 		script_nop, ASC_CMD_I_COMPLETE,
29252942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
29352889Sbostic 
29452889Sbostic 	/* get status and finish command */
29552942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
29652889Sbostic 		asc_get_status, ASC_CMD_MSG_ACPT,
29752942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
29852942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  8 */
29952889Sbostic 		asc_end, ASC_CMD_NOP,
30052942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
30152889Sbostic 
30252889Sbostic 	/* message in */
30352942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  9 */
30452942Sralph 		asc_msg_in, ASC_CMD_MSG_ACPT,
30552942Sralph 		&asc_scripts[SCRIPT_MSG_IN + 1]},
30652942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 10 */
30752889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
30852942Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
30952889Sbostic 
31052889Sbostic 	/* send synchonous negotiation reply */
31152942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/* 11 */
31252889Sbostic 		asc_replysync, ASC_CMD_XFER_INFO,
31352942Sralph 		&asc_scripts[SCRIPT_REPLY_SYNC]},
31452889Sbostic 
31552889Sbostic 	/* try to negotiate synchonous transfer parameters */
31652889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
31752889Sbostic 		asc_sendsync, ASC_CMD_XFER_INFO,
31853080Sralph 		&asc_scripts[SCRIPT_TRY_SYNC + 1]},
31953080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 13 */
32052889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
32153080Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
32253080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND),			/* 14 */
32353080Sralph 		script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
32453080Sralph 		&asc_scripts[SCRIPT_RESUME_NO_DATA]},
32552889Sbostic 
32652942Sralph 	/* handle a disconnect */
32752942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO),			/* 15 */
32852942Sralph 		asc_disconnect, ASC_CMD_ENABLE_SEL,
32952942Sralph 		&asc_scripts[SCRIPT_RESEL]},
33052942Sralph 
33152889Sbostic 	/* reselect sequence: this is just a placeholder so match fails */
33252942Sralph 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 16 */
33352889Sbostic 		script_nop, ASC_CMD_MSG_ACPT,
33452942Sralph 		&asc_scripts[SCRIPT_RESEL]},
33552889Sbostic 
33652942Sralph 	/* resume data in after a message */
33752942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 17 */
33852942Sralph 		asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
33952942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
34052942Sralph 
34152942Sralph 	/* resume partial DMA data in after a message */
34252942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 18 */
34352889Sbostic 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
34452942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
34552889Sbostic 
34652942Sralph 	/* resume data out after a message */
34752942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 19 */
34852942Sralph 		asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
34952942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
35052942Sralph 
35152942Sralph 	/* resume partial DMA data out after a message */
35252942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 20 */
35352889Sbostic 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
35452942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
35552942Sralph 
35652942Sralph 	/* resume after a message when there is no more data */
35752942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/* 21 */
35852942Sralph 		script_nop, ASC_CMD_I_COMPLETE,
35952942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
36052889Sbostic };
36152889Sbostic 
36252889Sbostic /*
36352889Sbostic  * State kept for each active SCSI device.
36452889Sbostic  */
36552889Sbostic typedef struct scsi_state {
36652889Sbostic 	script_t *script;	/* saved script while processing error */
36752889Sbostic 	int	statusByte;	/* status byte returned during STATUS_PHASE */
36852889Sbostic 	int	error;		/* errno to pass back to device driver */
36952889Sbostic 	u_char	*dmaBufAddr;	/* DMA buffer address */
37052889Sbostic 	u_int	dmaBufSize;	/* DMA buffer size */
37152889Sbostic 	int	dmalen;		/* amount to transfer in this chunk */
37252889Sbostic 	int	dmaresid;	/* amount not transfered if chunk suspended */
37352889Sbostic 	int	buflen;		/* total remaining amount of data to transfer */
37452889Sbostic 	char	*buf;		/* current pointer within scsicmd->buf */
37552889Sbostic 	int	flags;		/* see below */
37652889Sbostic 	int	msglen;		/* number of message bytes to read */
37752889Sbostic 	int	msgcnt;		/* number of message bytes received */
37852889Sbostic 	u_char	sync_period;	/* DMA synchronous period */
37952889Sbostic 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
38052889Sbostic 	u_char	msg_out;	/* next MSG_OUT byte to send */
38152889Sbostic 	u_char	msg_in[16];	/* buffer for multibyte messages */
38252889Sbostic } State;
38352889Sbostic 
38452889Sbostic /* state flags */
38552889Sbostic #define DISCONN		0x01	/* true if currently disconnected from bus */
38653080Sralph #define DMA_IN_PROGRESS	0x02	/* true if data DMA started */
38752889Sbostic #define DMA_IN		0x04	/* true if reading from SCSI device */
38852889Sbostic #define DMA_OUT		0x10	/* true if writing to SCSI device */
38952889Sbostic #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
39052889Sbostic #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
39152889Sbostic 
39252889Sbostic #define ASC_NCMD	7
39352889Sbostic /*
39452889Sbostic  * State kept for each active SCSI host interface (53C94).
39552889Sbostic  */
39652889Sbostic struct asc_softc {
39752889Sbostic 	asc_regmap_t	*regs;		/* chip address */
39852889Sbostic 	volatile int	*dmar;		/* DMA address register address */
399*56819Sralph 	u_char		*buff;		/* RAM buffer address (uncached) */
40052889Sbostic 	int		myid;		/* SCSI ID of this interface */
40152889Sbostic 	int		myidmask;	/* ~(1 << myid) */
40252889Sbostic 	int		state;		/* current SCSI connection state */
40352889Sbostic 	int		target;		/* target SCSI ID if busy */
40452889Sbostic 	script_t	*script;	/* next expected interrupt & action */
40552889Sbostic 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
40652889Sbostic 	State		st[ASC_NCMD];	/* state info for each active command */
407*56819Sralph 	void		(*dma_start)();	/* Start dma routine */
408*56819Sralph 	void		(*dma_end)();	/* End dma routine */
409*56819Sralph 	u_char		*dma_next;
410*56819Sralph 	int		dma_xfer;	/* Dma len still to go */
411*56819Sralph 	int		min_period;	/* Min transfer period clk/byte */
412*56819Sralph 	int		max_period;	/* Max transfer period clk/byte */
413*56819Sralph 	int		ccf;		/* CCF, whatever that really is? */
414*56819Sralph 	int		timeout_250;	/* 250ms timeout */
415*56819Sralph 	int		tb_ticks;	/* 4ns. ticks/tb channel ticks */
41652889Sbostic } asc_softc[NASC];
41752889Sbostic 
41852889Sbostic #define	ASC_STATE_IDLE		0	/* idle state */
41952889Sbostic #define	ASC_STATE_BUSY		1	/* selecting or currently connected */
42052889Sbostic #define ASC_STATE_TARGET	2	/* currently selected as target */
42152889Sbostic #define ASC_STATE_RESEL		3	/* currently waiting for reselect */
42252889Sbostic 
42352889Sbostic typedef struct asc_softc *asc_softc_t;
42452889Sbostic 
42552889Sbostic /*
426*56819Sralph  * Dma operations.
427*56819Sralph  */
428*56819Sralph #define	ASCDMA_READ	1
429*56819Sralph #define	ASCDMA_WRITE	2
430*56819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();
431*56819Sralph u_long asc_iobuf[33792];
432*56819Sralph 
433*56819Sralph /*
43452889Sbostic  * Definition of the controller for the auto-configuration program.
43552889Sbostic  */
43652889Sbostic int	asc_probe();
43752889Sbostic void	asc_start();
43852889Sbostic void	asc_intr();
43952889Sbostic struct	driver ascdriver = {
44052889Sbostic 	"asc", asc_probe, asc_start, 0, asc_intr,
44152889Sbostic };
44252889Sbostic 
44352889Sbostic /*
44452889Sbostic  * Test to see if device is present.
44552889Sbostic  * Return true if found and initialized ok.
44652889Sbostic  */
44752889Sbostic asc_probe(cp)
44852889Sbostic 	register struct pmax_ctlr *cp;
44952889Sbostic {
45052889Sbostic 	register asc_softc_t asc;
45152889Sbostic 	register asc_regmap_t *regs;
45252889Sbostic 	int unit, id, s, i;
453*56819Sralph 	u_int bufadr;
45452889Sbostic 
45552889Sbostic 	if ((unit = cp->pmax_unit) >= NASC)
45652889Sbostic 		return (0);
45752889Sbostic 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
45852889Sbostic 		return (0);
45952889Sbostic 	asc = &asc_softc[unit];
46052889Sbostic 
46152889Sbostic 	/*
46252889Sbostic 	 * Initialize hw descriptor, cache some pointers
46352889Sbostic 	 */
46452889Sbostic 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
46552889Sbostic 
466*56819Sralph 	/*
467*56819Sralph 	 * Set up machine dependencies.
468*56819Sralph 	 * 1) how to do dma
469*56819Sralph 	 * 2) timing based on turbochannel frequency
470*56819Sralph 	 */
471*56819Sralph 	switch (pmax_boardtype) {
472*56819Sralph 	case DS_3MIN:
473*56819Sralph 	case DS_MAXINE:
474*56819Sralph 	    if (unit == 0) {
475*56819Sralph 		bufadr = MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(asc_iobuf));
476*56819Sralph 		bufadr = (bufadr + NBPG - 1) & ~(NBPG - 1);
477*56819Sralph 		asc->buff = (u_char *)bufadr;
478*56819Sralph 		*((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR))
479*56819Sralph 			= -1;
480*56819Sralph 		*((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR))
481*56819Sralph 			= -1;
482*56819Sralph 		*((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR)) = 0;
483*56819Sralph 		asc->dma_start = asic_dma_start;
484*56819Sralph 		asc->dma_end = asic_dma_end;
485*56819Sralph 		break;
486*56819Sralph 	    }
487*56819Sralph 	    /*
488*56819Sralph 	     * Fall through for turbochannel option.
489*56819Sralph 	     */
490*56819Sralph 	case DS_3MAX:
491*56819Sralph 	default:
492*56819Sralph 	    asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
493*56819Sralph 	    asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
494*56819Sralph 	    asc->dma_start = tb_dma_start;
495*56819Sralph 	    asc->dma_end = tb_dma_end;
496*56819Sralph 	};
497*56819Sralph 	/*
498*56819Sralph 	 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and
499*56819Sralph 	 * maxine are 12.5Mhz.
500*56819Sralph 	 */
501*56819Sralph 	switch (pmax_boardtype) {
502*56819Sralph 	case DS_3MAX:
503*56819Sralph 		asc->min_period = ASC_MIN_PERIOD25;
504*56819Sralph 		asc->max_period = ASC_MAX_PERIOD25;
505*56819Sralph 		asc->ccf = ASC_CCF(25);
506*56819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);
507*56819Sralph 		asc->tb_ticks = 10;
508*56819Sralph 		break;
509*56819Sralph 	case DS_3MIN:
510*56819Sralph 	case DS_MAXINE:
511*56819Sralph 	default:
512*56819Sralph 		asc->min_period = ASC_MIN_PERIOD12;
513*56819Sralph 		asc->max_period = ASC_MAX_PERIOD12;
514*56819Sralph 		asc->ccf = ASC_CCF(13);
515*56819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);
516*56819Sralph 		asc->tb_ticks = 20;
517*56819Sralph 		break;
518*56819Sralph 	};
519*56819Sralph 
52052889Sbostic 	asc->state = ASC_STATE_IDLE;
52152889Sbostic 	asc->target = -1;
52252889Sbostic 
52352889Sbostic 	regs = asc->regs;
52452889Sbostic 
52552889Sbostic 	/*
52652889Sbostic 	 * Reset chip, fully.  Note that interrupts are already enabled.
52752889Sbostic 	 */
52852889Sbostic 	s = splbio();
52952889Sbostic 
53052889Sbostic 	/* preserve our ID for now */
53152889Sbostic 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
53252889Sbostic 	asc->myidmask = ~(1 << asc->myid);
53352889Sbostic 
53452889Sbostic 	asc_reset(asc, regs);
53552889Sbostic 
53652889Sbostic 	/*
53752889Sbostic 	 * Our SCSI id on the bus.
53852889Sbostic 	 * The user can set this via the prom on 3maxen/pmaxen.
53952889Sbostic 	 * If this changes it is easy to fix: make a default that
54052889Sbostic 	 * can be changed as boot arg.
54152889Sbostic 	 */
54252889Sbostic #ifdef	unneeded
54352889Sbostic 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
54452889Sbostic 			      (scsi_initiator_id[unit] & 0x7);
54552889Sbostic #endif
54652889Sbostic 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
54752889Sbostic 	splx(s);
54852889Sbostic 
54952889Sbostic 	/*
55052889Sbostic 	 * Statically partition the DMA buffer between targets.
55152889Sbostic 	 * This way we will eventually be able to attach/detach
55252889Sbostic 	 * drives on-fly.  And 18k/target is plenty for normal use.
55352889Sbostic 	 */
55452889Sbostic #define PER_TGT_DMA_SIZE	((ASC_RAM_SIZE/7) & ~(sizeof(int)-1))
55552889Sbostic 
55652889Sbostic 	/*
55752889Sbostic 	 * Give each target its own DMA buffer region.
55852889Sbostic 	 * We may want to try ping ponging buffers later.
55952889Sbostic 	 */
56052889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
56152889Sbostic 		asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i;
56252889Sbostic 		asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE;
56352889Sbostic 	}
56452889Sbostic 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
56552889Sbostic 		unit, cp->pmax_addr, cp->pmax_pri, id);
56652889Sbostic 	return (1);
56752889Sbostic }
56852889Sbostic 
56952889Sbostic /*
57052889Sbostic  * Start activity on a SCSI device.
57152889Sbostic  * We maintain information on each device separately since devices can
57252889Sbostic  * connect/disconnect during an operation.
57352889Sbostic  */
57452889Sbostic void
57552889Sbostic asc_start(scsicmd)
57652889Sbostic 	register ScsiCmd *scsicmd;	/* command to start */
57752889Sbostic {
57852889Sbostic 	register struct scsi_device *sdp = scsicmd->sd;
57952889Sbostic 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
58052889Sbostic 	int s;
58152889Sbostic 
58252889Sbostic 	s = splbio();
58352889Sbostic 	/*
58452889Sbostic 	 * Check if another command is already in progress.
58552889Sbostic 	 * We may have to change this if we allow SCSI devices with
58652889Sbostic 	 * separate LUNs.
58752889Sbostic 	 */
58852889Sbostic 	if (asc->cmd[sdp->sd_drive]) {
58952889Sbostic 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
59052889Sbostic 			sdp->sd_driver->d_name);
59152889Sbostic 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
59252889Sbostic 			scsicmd->buflen, 0);
59352889Sbostic 		splx(s);
59452889Sbostic 	}
59552889Sbostic 	asc->cmd[sdp->sd_drive] = scsicmd;
59652889Sbostic 	asc_startcmd(asc, sdp->sd_drive);
59752889Sbostic 	splx(s);
59852889Sbostic }
59952889Sbostic 
60052889Sbostic static void
60152889Sbostic asc_reset(asc, regs)
60252889Sbostic 	asc_softc_t asc;
60352889Sbostic 	asc_regmap_t *regs;
60452889Sbostic {
60552889Sbostic 
60652889Sbostic 	/*
60752889Sbostic 	 * Reset chip and wait till done
60852889Sbostic 	 */
60952889Sbostic 	regs->asc_cmd = ASC_CMD_RESET;
61052889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
61152889Sbostic 
61252889Sbostic 	/* spec says this is needed after reset */
61352889Sbostic 	regs->asc_cmd = ASC_CMD_NOP;
61452889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
61552889Sbostic 
61652889Sbostic 	/*
61752889Sbostic 	 * Set up various chip parameters
61852889Sbostic 	 */
619*56819Sralph 	regs->asc_ccf = asc->ccf;
62052889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
621*56819Sralph 	regs->asc_sel_timo = asc->timeout_250;
62252889Sbostic 	/* restore our ID */
62352889Sbostic 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
624*56819Sralph 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_SCSI2;
62552889Sbostic 	regs->asc_cnfg3 = 0;
62652889Sbostic 	/* zero anything else */
62752889Sbostic 	ASC_TC_PUT(regs, 0);
628*56819Sralph 	regs->asc_syn_p = asc->min_period;
62952889Sbostic 	regs->asc_syn_o = 0;	/* async for now */
63052889Sbostic 	MachEmptyWriteBuffer();
63152889Sbostic }
63252889Sbostic 
63352889Sbostic /*
63452889Sbostic  * Start a SCSI command on a target.
63552889Sbostic  */
63652889Sbostic static void
63752889Sbostic asc_startcmd(asc, target)
63852889Sbostic 	asc_softc_t asc;
63952889Sbostic 	int target;
64052889Sbostic {
64152889Sbostic 	register asc_regmap_t *regs;
64252889Sbostic 	register ScsiCmd *scsicmd;
64352889Sbostic 	register State *state;
64452889Sbostic 	int len;
64552889Sbostic 
64652889Sbostic 	/*
64752889Sbostic 	 * See if another target is currently selected on this SCSI bus.
64852889Sbostic 	 */
64952889Sbostic 	if (asc->target >= 0)
65052889Sbostic 		return;
65152889Sbostic 
65252889Sbostic 	regs = asc->regs;
65352889Sbostic 
65452889Sbostic 	/*
65552889Sbostic 	 * Check to see if a reselection is in progress and if so,
65652889Sbostic 	 * try to cancel it or respond to the reselection if it won.
65752889Sbostic 	 */
65852889Sbostic 	if (asc->state == ASC_STATE_RESEL) {
65952889Sbostic 		regs->asc_cmd = ASC_CMD_DISABLE_SEL;
660*56819Sralph 		readback(regs->asc_cmd);
66152889Sbostic 		while (!(regs->asc_status & ASC_CSR_INT))
66252889Sbostic 			DELAY(1);
66352889Sbostic 		asc_intr(asc - asc_softc);
66452889Sbostic 		/* we will be busy if a reselecting device won */
66552889Sbostic 		if (asc->state == ASC_STATE_BUSY)
66652889Sbostic 			return;
66752889Sbostic 	}
66852889Sbostic 
66952889Sbostic 	asc->state = ASC_STATE_BUSY;
67052889Sbostic 	asc->target = target;
67152889Sbostic 
67252889Sbostic 	/* cache some pointers */
67352889Sbostic 	scsicmd = asc->cmd[target];
67452889Sbostic 	state = &asc->st[target];
67552889Sbostic 
67652889Sbostic #ifdef DEBUG
67752889Sbostic 	if (asc_debug > 1) {
67852889Sbostic 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
67952889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
68052889Sbostic 			scsicmd->cmd[0], scsicmd->buflen);
68152889Sbostic 	}
68252889Sbostic 	asc_debug_cmd = scsicmd->cmd[0];
68352889Sbostic 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
68452889Sbostic 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
68552889Sbostic 			(scsicmd->cmd[3] << 16) |
68652889Sbostic 			(scsicmd->cmd[4] << 8) |
68752889Sbostic 			scsicmd->cmd[5];
68852889Sbostic 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
68952889Sbostic 	}
69053080Sralph 	asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd);
69152889Sbostic 	asc_logp->target = asc->target;
69252889Sbostic 	asc_logp->state = 0;
69353080Sralph 	asc_logp->msg = 0xff;
69452889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
69552889Sbostic 		asc_logp = asc_log;
69652889Sbostic #endif
69752889Sbostic 
69852889Sbostic 	/*
69952889Sbostic 	 * Init the chip and target state.
70052889Sbostic 	 */
70152889Sbostic 	regs->asc_cmd = ASC_CMD_FLUSH;
702*56819Sralph 	readback(regs->asc_cmd);
703*56819Sralph 	DELAY(2);
70453080Sralph 	state->flags = state->flags & DID_SYNC;
70552889Sbostic 	state->error = 0;
70652889Sbostic 	state->script = (script_t *)0;
70752889Sbostic 	state->msg_out = SCSI_NO_OP;
70852889Sbostic 
70952889Sbostic 	/*
71052889Sbostic 	 * Copy command data to the DMA buffer.
71152889Sbostic 	 */
71252889Sbostic 	len = scsicmd->cmdlen;
71352889Sbostic 	state->dmalen = len;
71452889Sbostic 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
71552889Sbostic 
71652889Sbostic 	/* check for simple SCSI command with no data transfer */
71752889Sbostic 	if ((state->buflen = scsicmd->buflen) == 0) {
71852889Sbostic 		/* check for sync negotiation */
71952889Sbostic 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
72052889Sbostic 		    !(state->flags & DID_SYNC)) {
72152889Sbostic 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
72252889Sbostic 			state->flags |= TRY_SYNC;
72352889Sbostic 		} else
72452889Sbostic 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
72552889Sbostic 		state->buf = (char *)0;
72652889Sbostic 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
72752889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
72853080Sralph 		state->buf = scsicmd->buf;
72952889Sbostic 		state->flags |= DMA_OUT;
73052889Sbostic 	} else {
73152889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
73252889Sbostic 		state->buf = scsicmd->buf;
73352889Sbostic 		state->flags |= DMA_IN;
73452889Sbostic 	}
73552889Sbostic 
73652889Sbostic 	/* preload the FIFO with the message to be sent */
73752942Sralph 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
738*56819Sralph 	MachEmptyWriteBuffer();
73952889Sbostic 
74052889Sbostic 	/* start the asc */
741*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
74252889Sbostic 	ASC_TC_PUT(regs, len);
743*56819Sralph 	readback(regs->asc_cmd);
74452889Sbostic 
74552889Sbostic 	regs->asc_dbus_id = target;
746*56819Sralph 	readback(regs->asc_dbus_id);
74752889Sbostic 	regs->asc_syn_p = state->sync_period;
748*56819Sralph 	readback(regs->asc_syn_p);
74952889Sbostic 	regs->asc_syn_o = state->sync_offset;
750*56819Sralph 	readback(regs->asc_syn_o);
75152889Sbostic 
75252889Sbostic 	if (state->flags & TRY_SYNC)
75353080Sralph 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
75452889Sbostic 	else
75552889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
756*56819Sralph 	readback(regs->asc_cmd);
75752889Sbostic }
75852889Sbostic 
75952889Sbostic /*
76052889Sbostic  * Interrupt routine
76152889Sbostic  *	Take interrupts from the chip
76252889Sbostic  *
76352889Sbostic  * Implementation:
76452889Sbostic  *	Move along the current command's script if
76552889Sbostic  *	all is well, invoke error handler if not.
76652889Sbostic  */
76752889Sbostic void
76852889Sbostic asc_intr(unit)
76952889Sbostic 	int unit;
77052889Sbostic {
77152889Sbostic 	register asc_softc_t asc = &asc_softc[unit];
77252889Sbostic 	register asc_regmap_t *regs = asc->regs;
77352889Sbostic 	register State *state;
77452889Sbostic 	register script_t *scpt;
77552889Sbostic 	register int ss, ir, status;
77652889Sbostic 
77752889Sbostic 	/* collect ephemeral information */
77852889Sbostic 	status = regs->asc_status;
77953080Sralph again:
78052889Sbostic 	ss = regs->asc_ss;
78152889Sbostic 	ir = regs->asc_intr;	/* this resets the previous two */
78252889Sbostic 	scpt = asc->script;
78352889Sbostic 
78452889Sbostic #ifdef DEBUG
78552889Sbostic 	asc_logp->status = PACK(unit, status, ss, ir);
78652889Sbostic 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
78752889Sbostic 	asc_logp->state = scpt - asc_scripts;
78852889Sbostic 	asc_logp->msg = -1;
78952889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
79052889Sbostic 		asc_logp = asc_log;
79152889Sbostic 	if (asc_debug > 2)
79252889Sbostic 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
79352889Sbostic 			status, ss, ir, scpt - asc_scripts, scpt->condition);
79452889Sbostic #endif
79552889Sbostic 
79652889Sbostic 	/* check the expected state */
79752889Sbostic 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
79852889Sbostic 		/*
79952889Sbostic 		 * Perform the appropriate operation, then proceed.
80052889Sbostic 		 */
80152889Sbostic 		if ((*scpt->action)(asc, status, ss, ir)) {
80252889Sbostic 			regs->asc_cmd = scpt->command;
803*56819Sralph 			readback(regs->asc_cmd);
80452889Sbostic 			asc->script = scpt->next;
80552889Sbostic 		}
80652889Sbostic 		goto done;
80752889Sbostic 	}
80852889Sbostic 
80952889Sbostic 	/* check for message in or out */
81052889Sbostic 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
81152889Sbostic 		register int len, fifo;
81252889Sbostic 
81352889Sbostic 		state = &asc->st[asc->target];
81452889Sbostic 		switch (ASC_PHASE(status)) {
81553080Sralph 		case ASC_PHASE_DATAI:
81653080Sralph 		case ASC_PHASE_DATAO:
81753080Sralph 			ASC_TC_GET(regs, len);
81853080Sralph 			fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
81953080Sralph 			printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
82053080Sralph 				state->buflen, state->dmalen, len, fifo);
82153080Sralph 			goto abort;
82253080Sralph 
82352889Sbostic 		case ASC_PHASE_MSG_IN:
82452889Sbostic 			break;
82552889Sbostic 
82652889Sbostic 		case ASC_PHASE_MSG_OUT:
82752889Sbostic 			regs->asc_fifo = state->msg_out;
82852889Sbostic 			state->msg_out = SCSI_NO_OP;
82952889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
830*56819Sralph 			readback(regs->asc_cmd);
83152889Sbostic 			goto done;
83252889Sbostic 
83352889Sbostic 		case ASC_PHASE_STATUS:
83452889Sbostic 			/* probably an error in the SCSI command */
83552889Sbostic 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
83652889Sbostic 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
837*56819Sralph 			readback(regs->asc_cmd);
83852889Sbostic 			goto done;
83952889Sbostic 
84052889Sbostic 		default:
84152889Sbostic 			goto abort;
84252889Sbostic 		}
84352889Sbostic 
84452889Sbostic 		if (state->script)
84552889Sbostic 			goto abort;
84652889Sbostic 
84752889Sbostic 		/* check for DMA in progress */
84852889Sbostic 		ASC_TC_GET(regs, len);
84952889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
85052889Sbostic 		/* flush any data in the FIFO */
85152889Sbostic 		if (fifo) {
85253080Sralph 			if (state->flags & DMA_OUT)
85353080Sralph 				len += fifo;
85453080Sralph 			else if (state->flags & DMA_IN) {
85553080Sralph 				u_char *cp;
85653080Sralph 
85753080Sralph 				printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
85853080Sralph 					state->dmalen, len, fifo); /* XXX */
85953080Sralph 				len += fifo;
86053080Sralph 				cp = state->dmaBufAddr + (state->dmalen - len);
86153080Sralph 				while (fifo-- > 0)
86253080Sralph 					*cp++ = regs->asc_fifo;
86353080Sralph 			} else
86453080Sralph 				printf("asc_intr: dmalen %d len %d fifo %d\n",
86553080Sralph 					state->dmalen, len, fifo); /* XXX */
86652889Sbostic 			regs->asc_cmd = ASC_CMD_FLUSH;
867*56819Sralph 			readback(regs->asc_cmd);
86852889Sbostic 			MachEmptyWriteBuffer();
869*56819Sralph 			DELAY(2);
87052889Sbostic 		}
87152889Sbostic 		if (len) {
87252889Sbostic 			/* save number of bytes still to be sent or received */
87352889Sbostic 			state->dmaresid = len;
87452889Sbostic 			/* setup state to resume to */
87552889Sbostic 			if (state->flags & DMA_IN)
87652889Sbostic 				state->script =
87752889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
87852889Sbostic 			else if (state->flags & DMA_OUT)
87952889Sbostic 				state->script =
88052889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
88152889Sbostic 			else
88252889Sbostic 				state->script = asc->script;
88352889Sbostic 		} else {
88452889Sbostic 			/* setup state to resume to */
88552942Sralph 			if (state->flags & DMA_IN) {
88653080Sralph 				if (state->flags & DMA_IN_PROGRESS) {
88753080Sralph 					state->flags &= ~DMA_IN_PROGRESS;
888*56819Sralph 					(*asc->dma_end)(asc, state, ASCDMA_READ);
88952942Sralph 					len = state->dmalen;
89052942Sralph 					bcopy(state->dmaBufAddr, state->buf,
89152942Sralph 						len);
89252942Sralph 					state->buf += len;
89352942Sralph 					state->buflen -= len;
89453080Sralph 				}
89552942Sralph 				if (state->buflen)
89652942Sralph 					state->script =
89752942Sralph 					    &asc_scripts[SCRIPT_RESUME_IN];
89852942Sralph 				else
89952942Sralph 					state->script =
90052942Sralph 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
90152942Sralph 			} else if (state->flags & DMA_OUT) {
90252942Sralph 				/*
90352942Sralph 				 * If this is the last chunk, the next expected
90452942Sralph 				 * state is to get status.
90552942Sralph 				 */
90653080Sralph 				if (state->flags & DMA_IN_PROGRESS) {
90753080Sralph 					state->flags &= ~DMA_IN_PROGRESS;
908*56819Sralph 					(*asc->dma_end)(asc, state, ASCDMA_WRITE);
90953080Sralph 					len = state->dmalen;
91053080Sralph 					state->buf += len;
91153080Sralph 					state->buflen -= len;
91253080Sralph 				}
91352942Sralph 				if (state->buflen)
91452942Sralph 					state->script =
91552942Sralph 					    &asc_scripts[SCRIPT_RESUME_OUT];
91652942Sralph 				else
91752942Sralph 					state->script =
91852942Sralph 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
91953080Sralph 			} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
92053080Sralph 				state->script =
92153080Sralph 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
92253080Sralph 			else
92352889Sbostic 				state->script = asc->script;
92452889Sbostic 		}
92552889Sbostic 
92652889Sbostic 		/* setup to receive a message */
92752889Sbostic 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
92852889Sbostic 		state->msglen = 0;
92952889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO;
930*56819Sralph 		readback(regs->asc_cmd);
93152889Sbostic 		goto done;
93252889Sbostic 	}
93352889Sbostic 
93452889Sbostic 	/* check for SCSI bus reset */
93552889Sbostic 	if (ir & ASC_INT_RESET) {
93652889Sbostic 		register int i;
93752889Sbostic 
93852889Sbostic 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
93952889Sbostic 		/* need to flush any pending commands */
94052889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
94152889Sbostic 			if (!asc->cmd[i])
94252889Sbostic 				continue;
94352889Sbostic 			asc->st[i].error = EIO;
94452889Sbostic 			asc_end(asc, 0, 0, 0);
94552889Sbostic 		}
94652889Sbostic 		/* rearbitrate synchronous offset */
94752889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
94852889Sbostic 			asc->st[i].sync_offset = 0;
94952889Sbostic 			asc->st[i].flags = 0;
95052889Sbostic 		}
95152889Sbostic 		asc->target = -1;
95252889Sbostic 		return;
95352889Sbostic 	}
95452889Sbostic 
95552889Sbostic 	/* check for command errors */
95652889Sbostic 	if (ir & ASC_INT_ILL)
95752889Sbostic 		goto abort;
95852889Sbostic 
95952889Sbostic 	/* check for disconnect */
96052889Sbostic 	if (ir & ASC_INT_DISC) {
96152889Sbostic 		state = &asc->st[asc->target];
96252889Sbostic 		switch (ASC_SS(ss)) {
96352889Sbostic 		case 0: /* device did not respond */
96452889Sbostic 			state->error = ENXIO;
96552889Sbostic 			asc_end(asc, status, ss, ir);
96652889Sbostic 			return;
96752889Sbostic 
96852889Sbostic 		default:
96952889Sbostic 			goto abort;
97052889Sbostic 		}
97152889Sbostic 	}
97252889Sbostic 
97352889Sbostic 	/* check for reselect */
97452889Sbostic 	if (ir & ASC_INT_RESEL) {
97552889Sbostic 		unsigned fifo, id, msg;
97652889Sbostic 
97752889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
97852889Sbostic 		if (fifo < 2)
97952889Sbostic 			goto abort;
98052889Sbostic 		/* read unencoded SCSI ID and convert to binary */
98152889Sbostic 		msg = regs->asc_fifo & asc->myidmask;
98252889Sbostic 		for (id = 0; (msg & 1) == 0; id++)
98352889Sbostic 			msg >>= 1;
98452889Sbostic 		/* read identify message */
98552889Sbostic 		msg = regs->asc_fifo;
98652889Sbostic #ifdef DEBUG
98752889Sbostic 		if (asc_logp == asc_log)
98852889Sbostic 			asc_log[NLOG - 1].msg = msg;
98952889Sbostic 		else
99052889Sbostic 			asc_logp[-1].msg = msg;
99152889Sbostic #endif
99252889Sbostic 		if (asc->state != ASC_STATE_RESEL)
99352889Sbostic 			goto abort;
99452889Sbostic 		asc->state = ASC_STATE_BUSY;
99552889Sbostic 		asc->target = id;
99652889Sbostic 		state = &asc->st[id];
99752889Sbostic 		asc->script = state->script;
99852889Sbostic 		state->script = (script_t *)0;
99952889Sbostic 		if (!(state->flags & DISCONN))
100052889Sbostic 			goto abort;
100152889Sbostic 		state->flags &= ~DISCONN;
100253080Sralph 		regs->asc_syn_p = state->sync_period;
100353080Sralph 		regs->asc_syn_o = state->sync_offset;
100452889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1005*56819Sralph 		readback(regs->asc_cmd);
100652889Sbostic 		goto done;
100752889Sbostic 	}
100852889Sbostic 
100952889Sbostic 	/* check if we are being selected as a target */
101052889Sbostic 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
101152889Sbostic 		goto abort;
101252889Sbostic 
101352889Sbostic 	/* must be just a ASC_INT_FC */
101452889Sbostic done:
101552889Sbostic 	MachEmptyWriteBuffer();
101653080Sralph 	/* watch out for HW race conditions and setup & hold time violations */
101753080Sralph 	ir = regs->asc_status;
101853080Sralph 	while (ir != (status = regs->asc_status))
101953080Sralph 		ir = status;
102053080Sralph 	if (status & ASC_CSR_INT)
102152889Sbostic 		goto again;
102252889Sbostic 	return;
102352889Sbostic 
102452889Sbostic abort:
102552889Sbostic #ifdef DEBUG
102652889Sbostic 	asc_DumpLog("asc_intr");
102752889Sbostic #endif
102852889Sbostic #if 0
102952889Sbostic 	panic("asc_intr");
103052889Sbostic #else
103152889Sbostic 	for (;;);
103252889Sbostic #endif
103352889Sbostic }
103452889Sbostic 
103552889Sbostic /*
103652889Sbostic  * All the many little things that the interrupt
103752889Sbostic  * routine might switch to.
103852889Sbostic  */
103952889Sbostic 
104052889Sbostic /* ARGSUSED */
104152889Sbostic static int
104252889Sbostic script_nop(asc, status, ss, ir)
104352889Sbostic 	register asc_softc_t asc;
104452889Sbostic 	register int status, ss, ir;
104552889Sbostic {
104652889Sbostic 	return (1);
104752889Sbostic }
104852889Sbostic 
104952889Sbostic /* ARGSUSED */
105052889Sbostic static int
105152889Sbostic asc_get_status(asc, status, ss, ir)
105252889Sbostic 	register asc_softc_t asc;
105352889Sbostic 	register int status, ss, ir;
105452889Sbostic {
105552889Sbostic 	register asc_regmap_t *regs = asc->regs;
105652889Sbostic 	register int data;
105752889Sbostic 
105852889Sbostic 	/*
105952889Sbostic 	 * Get the last two bytes in the FIFO.
106052889Sbostic 	 */
106152889Sbostic 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
106252889Sbostic 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
106352889Sbostic 		if (data < 2) {
106452889Sbostic 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
1065*56819Sralph 			readback(asc->regs->asc_cmd);
106652889Sbostic 			return (0);
106752889Sbostic 		}
106852889Sbostic 		do {
106952889Sbostic 			data = regs->asc_fifo;
107052889Sbostic 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
107152889Sbostic 	}
107252889Sbostic 
107352889Sbostic 	/* save the status byte */
107452889Sbostic 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
107552889Sbostic #ifdef DEBUG
107652889Sbostic 	if (asc_logp == asc_log)
107752889Sbostic 		asc_log[NLOG - 1].msg = data;
107852889Sbostic 	else
107952889Sbostic 		asc_logp[-1].msg = data;
108052889Sbostic #endif
108152889Sbostic 
108252889Sbostic 	/* get the (presumed) command_complete message */
108352889Sbostic 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
108452889Sbostic 		return (1);
108552889Sbostic 
108652889Sbostic #ifdef DEBUG
108752889Sbostic 	printf("asc_get_status: status %x cmd %x\n",
108852889Sbostic 		asc->st[asc->target].statusByte, data);
108952889Sbostic 	asc_DumpLog("asc_get_status");
109052889Sbostic #endif
109152889Sbostic 	return (0);
109252889Sbostic }
109352889Sbostic 
109452889Sbostic /* ARGSUSED */
109552889Sbostic static int
109652889Sbostic asc_end(asc, status, ss, ir)
109752889Sbostic 	register asc_softc_t asc;
109852889Sbostic 	register int status, ss, ir;
109952889Sbostic {
110052889Sbostic 	register ScsiCmd *scsicmd;
110152889Sbostic 	register State *state;
110252889Sbostic 	register int i, target;
110352889Sbostic 
110452889Sbostic 	asc->state = ASC_STATE_IDLE;
110552889Sbostic 	target = asc->target;
110652889Sbostic 	asc->target = -1;
110752889Sbostic 	scsicmd = asc->cmd[target];
110852889Sbostic 	asc->cmd[target] = (ScsiCmd *)0;
110952889Sbostic 	state = &asc->st[target];
111052889Sbostic 
111152889Sbostic #ifdef DEBUG
111252889Sbostic 	if (asc_debug > 1) {
111352889Sbostic 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
111452889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
111552889Sbostic 			scsicmd->cmd[0], state->error, state->buflen);
111652889Sbostic 	}
111752889Sbostic #endif
111852889Sbostic #ifdef DIAGNOSTIC
111952889Sbostic 	if (target < 0 || !scsicmd)
112052889Sbostic 		panic("asc_end");
112152889Sbostic #endif
112252889Sbostic 
112352889Sbostic 	/* look for disconnected devices */
112452889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
112552889Sbostic 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
112652889Sbostic 			continue;
112752889Sbostic 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1128*56819Sralph 		readback(asc->regs->asc_cmd);
112952889Sbostic 		asc->state = ASC_STATE_RESEL;
113052889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESEL];
113152889Sbostic 		break;
113252889Sbostic 	}
113352889Sbostic 
113452889Sbostic 	/* look for another device that is ready */
113552889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
113652889Sbostic 		/* don't restart a disconnected command */
113752889Sbostic 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
113852889Sbostic 			continue;
113952889Sbostic 		asc_startcmd(asc, i);
114052889Sbostic 		break;
114152889Sbostic 	}
114252889Sbostic 
114352889Sbostic 	/* signal device driver that the command is done */
114452889Sbostic 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
114552889Sbostic 		state->buflen, state->statusByte);
114652889Sbostic 
114752889Sbostic 	return (0);
114852889Sbostic }
114952889Sbostic 
115052889Sbostic /* ARGSUSED */
115152889Sbostic static int
115252889Sbostic asc_dma_in(asc, status, ss, ir)
115352889Sbostic 	register asc_softc_t asc;
115452889Sbostic 	register int status, ss, ir;
115552889Sbostic {
115652889Sbostic 	register asc_regmap_t *regs = asc->regs;
115752889Sbostic 	register State *state = &asc->st[asc->target];
115853080Sralph 	register int len;
115952889Sbostic 
116052889Sbostic 	/* check for previous chunk in buffer */
116153080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
116252889Sbostic 		/*
116352889Sbostic 		 * Only count bytes that have been copied to memory.
116452889Sbostic 		 * There may be some bytes in the FIFO if synchonous transfers
116552889Sbostic 		 * are in progress.
116652889Sbostic 		 */
1167*56819Sralph 		(*asc->dma_end)(asc, state, ASCDMA_READ);
116852889Sbostic 		ASC_TC_GET(regs, len);
116952889Sbostic 		len = state->dmalen - len;
117052889Sbostic 		bcopy(state->dmaBufAddr, state->buf, len);
117152889Sbostic 		state->buf += len;
117252889Sbostic 		state->buflen -= len;
117353080Sralph 	}
117452889Sbostic 
117552942Sralph 	/* setup to start reading the next chunk */
117652889Sbostic 	len = state->buflen;
117752889Sbostic 	if (len > state->dmaBufSize)
117852889Sbostic 		len = state->dmaBufSize;
117952889Sbostic 	state->dmalen = len;
1180*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
118152889Sbostic 	ASC_TC_PUT(regs, len);
118252942Sralph #ifdef DEBUG
118352942Sralph 	if (asc_debug > 2)
118452942Sralph 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
118552942Sralph #endif
118652942Sralph 
118752942Sralph 	/* check for next chunk */
118853080Sralph 	state->flags |= DMA_IN_PROGRESS;
118952889Sbostic 	if (len != state->buflen) {
119052889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1191*56819Sralph 		readback(regs->asc_cmd);
119252942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
119352889Sbostic 		return (0);
119452889Sbostic 	}
119552889Sbostic 	return (1);
119652889Sbostic }
119752889Sbostic 
119852889Sbostic /* ARGSUSED */
119952889Sbostic static int
120052889Sbostic asc_last_dma_in(asc, status, ss, ir)
120152889Sbostic 	register asc_softc_t asc;
120252889Sbostic 	register int status, ss, ir;
120352889Sbostic {
120452889Sbostic 	register asc_regmap_t *regs = asc->regs;
120552889Sbostic 	register State *state = &asc->st[asc->target];
120652889Sbostic 	register int len, fifo;
120752889Sbostic 
120852889Sbostic 	/* copy data from buffer to main memory */
1209*56819Sralph 	(*asc->dma_end)(asc, state, ASCDMA_READ);
121052889Sbostic 	ASC_TC_GET(regs, len);
121152889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
121252889Sbostic #ifdef DEBUG
121352942Sralph 	if (asc_debug > 2)
121452889Sbostic 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
121552889Sbostic 			state->buflen, state->dmalen, len, fifo);
121652889Sbostic #endif
121752889Sbostic 	if (fifo) {
121852942Sralph 		/* device must be trying to send more than we expect */
121952889Sbostic 		regs->asc_cmd = ASC_CMD_FLUSH;
1220*56819Sralph 		readback(regs->asc_cmd);
122152889Sbostic 		MachEmptyWriteBuffer();
122252889Sbostic 	}
122353080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
122452889Sbostic 	len = state->dmalen - len;
122552889Sbostic 	state->buflen -= len;
122652889Sbostic 	bcopy(state->dmaBufAddr, state->buf, len);
122752889Sbostic 
122852889Sbostic 	return (1);
122952889Sbostic }
123052889Sbostic 
123152889Sbostic /* ARGSUSED */
123252889Sbostic static int
123352942Sralph asc_resume_in(asc, status, ss, ir)
123452942Sralph 	register asc_softc_t asc;
123552942Sralph 	register int status, ss, ir;
123652942Sralph {
123752942Sralph 	register asc_regmap_t *regs = asc->regs;
123852942Sralph 	register State *state = &asc->st[asc->target];
123952942Sralph 	register int len;
124052942Sralph 
124152942Sralph 	/* setup to start reading the next chunk */
124252942Sralph 	len = state->buflen;
124352942Sralph 	if (len > state->dmaBufSize)
124452942Sralph 		len = state->dmaBufSize;
124552942Sralph 	state->dmalen = len;
1246*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
124752942Sralph 	ASC_TC_PUT(regs, len);
124852942Sralph #ifdef DEBUG
124952942Sralph 	if (asc_debug > 2)
125052942Sralph 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
125152942Sralph 			len);
125252942Sralph #endif
125352942Sralph 
125452942Sralph 	/* check for next chunk */
125553080Sralph 	state->flags |= DMA_IN_PROGRESS;
125652942Sralph 	if (len != state->buflen) {
125752942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1258*56819Sralph 		readback(regs->asc_cmd);
125952942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
126052942Sralph 		return (0);
126152942Sralph 	}
126252942Sralph 	return (1);
126352942Sralph }
126452942Sralph 
126552942Sralph /* ARGSUSED */
126652942Sralph static int
126752889Sbostic asc_resume_dma_in(asc, status, ss, ir)
126852889Sbostic 	register asc_softc_t asc;
126952889Sbostic 	register int status, ss, ir;
127052889Sbostic {
127152889Sbostic 	register asc_regmap_t *regs = asc->regs;
127252889Sbostic 	register State *state = &asc->st[asc->target];
127352889Sbostic 	register int len, off;
127452889Sbostic 
127552889Sbostic 	/* setup to finish reading the current chunk */
127652889Sbostic 	len = state->dmaresid;
127752889Sbostic 	off = state->dmalen - len;
127852889Sbostic 	if ((off & 1) && state->sync_offset) {
127952889Sbostic 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
128052889Sbostic 			state->dmalen, len, off); /* XXX */
128152889Sbostic 		regs->asc_res_fifo = state->dmaBufAddr[off];
128252889Sbostic 	}
1283*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
128452889Sbostic 	ASC_TC_PUT(regs, len);
128552942Sralph #ifdef DEBUG
128652942Sralph 	if (asc_debug > 2)
128752942Sralph 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
128852942Sralph 			state->dmalen, state->buflen, len, off);
128952942Sralph #endif
129052942Sralph 
129152942Sralph 	/* check for next chunk */
129253080Sralph 	state->flags |= DMA_IN_PROGRESS;
129352889Sbostic 	if (state->dmalen != state->buflen) {
129452889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1295*56819Sralph 		readback(regs->asc_cmd);
129652942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
129752889Sbostic 		return (0);
129852889Sbostic 	}
129952889Sbostic 	return (1);
130052889Sbostic }
130152889Sbostic 
130252889Sbostic /* ARGSUSED */
130352889Sbostic static int
130452889Sbostic asc_dma_out(asc, status, ss, ir)
130552889Sbostic 	register asc_softc_t asc;
130652889Sbostic 	register int status, ss, ir;
130752889Sbostic {
130852889Sbostic 	register asc_regmap_t *regs = asc->regs;
130952889Sbostic 	register State *state = &asc->st[asc->target];
131052889Sbostic 	register int len, fifo;
131152889Sbostic 
131253080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
131352889Sbostic 		/* check to be sure previous chunk was finished */
131452889Sbostic 		ASC_TC_GET(regs, len);
131552889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
131652889Sbostic 		if (len || fifo)
131752889Sbostic 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
131852889Sbostic 				state->buflen, state->dmalen, len, fifo); /* XXX */
131952889Sbostic 		len += fifo;
132052889Sbostic 		len = state->dmalen - len;
132153080Sralph 		state->buf += len;
132252889Sbostic 		state->buflen -= len;
132353080Sralph 	}
132452889Sbostic 
132553080Sralph 	/* setup for this chunck */
132653080Sralph 	len = state->buflen;
132753080Sralph 	if (len > state->dmaBufSize)
132853080Sralph 		len = state->dmaBufSize;
132953080Sralph 	state->dmalen = len;
133053080Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
1331*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
133252942Sralph 	ASC_TC_PUT(regs, len);
133352889Sbostic #ifdef DEBUG
133452889Sbostic 	if (asc_debug > 2)
133552942Sralph 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
133652889Sbostic #endif
133752889Sbostic 
133852889Sbostic 	/* check for next chunk */
133953080Sralph 	state->flags |= DMA_IN_PROGRESS;
134052889Sbostic 	if (len != state->buflen) {
134152889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1342*56819Sralph 		readback(regs->asc_cmd);
134352942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
134452889Sbostic 		return (0);
134552889Sbostic 	}
134652889Sbostic 	return (1);
134752889Sbostic }
134852889Sbostic 
134952889Sbostic /* ARGSUSED */
135052889Sbostic static int
135152889Sbostic asc_last_dma_out(asc, status, ss, ir)
135252889Sbostic 	register asc_softc_t asc;
135352889Sbostic 	register int status, ss, ir;
135452889Sbostic {
135552889Sbostic 	register asc_regmap_t *regs = asc->regs;
135652889Sbostic 	register State *state = &asc->st[asc->target];
135752889Sbostic 	register int len, fifo;
135852889Sbostic 
135952889Sbostic 	ASC_TC_GET(regs, len);
136052889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
136152889Sbostic #ifdef DEBUG
136252889Sbostic 	if (asc_debug > 2)
136352889Sbostic 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
136453080Sralph 			state->buflen, state->dmalen, len, fifo);
136552942Sralph #endif
136652942Sralph 	if (fifo) {
136752942Sralph 		len += fifo;
136852942Sralph 		regs->asc_cmd = ASC_CMD_FLUSH;
1369*56819Sralph 		readback(regs->asc_cmd);
137052942Sralph 		MachEmptyWriteBuffer();
137152942Sralph 	}
137253080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
137352889Sbostic 	len = state->dmalen - len;
137452889Sbostic 	state->buflen -= len;
137552889Sbostic 	return (1);
137652889Sbostic }
137752889Sbostic 
137852889Sbostic /* ARGSUSED */
137952889Sbostic static int
138052942Sralph asc_resume_out(asc, status, ss, ir)
138152942Sralph 	register asc_softc_t asc;
138252942Sralph 	register int status, ss, ir;
138352942Sralph {
138452942Sralph 	register asc_regmap_t *regs = asc->regs;
138552942Sralph 	register State *state = &asc->st[asc->target];
138652942Sralph 	register int len;
138752942Sralph 
138852942Sralph 	/* setup for this chunck */
138952942Sralph 	len = state->buflen;
139052942Sralph 	if (len > state->dmaBufSize)
139152942Sralph 		len = state->dmaBufSize;
139252942Sralph 	state->dmalen = len;
139352942Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
1394*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
139552942Sralph 	ASC_TC_PUT(regs, len);
139652942Sralph #ifdef DEBUG
139752942Sralph 	if (asc_debug > 2)
139852942Sralph 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
139952942Sralph 			len);
140052942Sralph #endif
140152942Sralph 
140252942Sralph 	/* check for next chunk */
140353080Sralph 	state->flags |= DMA_IN_PROGRESS;
140452942Sralph 	if (len != state->buflen) {
140552942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1406*56819Sralph 		readback(regs->asc_cmd);
140752942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
140852942Sralph 		return (0);
140952942Sralph 	}
141052942Sralph 	return (1);
141152942Sralph }
141252942Sralph 
141352942Sralph /* ARGSUSED */
141452942Sralph static int
141552889Sbostic asc_resume_dma_out(asc, status, ss, ir)
141652889Sbostic 	register asc_softc_t asc;
141752889Sbostic 	register int status, ss, ir;
141852889Sbostic {
141952889Sbostic 	register asc_regmap_t *regs = asc->regs;
142052889Sbostic 	register State *state = &asc->st[asc->target];
142152889Sbostic 	register int len, off;
142252889Sbostic 
142352889Sbostic 	/* setup to finish writing this chunk */
142452889Sbostic 	len = state->dmaresid;
142552889Sbostic 	off = state->dmalen - len;
142652889Sbostic 	if (off & 1) {
142752889Sbostic 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
142852889Sbostic 			state->dmalen, len, off); /* XXX */
142952889Sbostic 		regs->asc_fifo = state->dmaBufAddr[off];
143052889Sbostic 		off++;
143152889Sbostic 		len--;
143252889Sbostic 	}
1433*56819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
143452889Sbostic 	ASC_TC_PUT(regs, len);
143552942Sralph #ifdef DEBUG
143652942Sralph 	if (asc_debug > 2)
143752942Sralph 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
143852942Sralph 			state->dmalen, state->buflen, len, off);
143952942Sralph #endif
144052942Sralph 
144152942Sralph 	/* check for next chunk */
144253080Sralph 	state->flags |= DMA_IN_PROGRESS;
144352889Sbostic 	if (state->dmalen != state->buflen) {
144452889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1445*56819Sralph 		readback(regs->asc_cmd);
144652942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
144752889Sbostic 		return (0);
144852889Sbostic 	}
144952889Sbostic 	return (1);
145052889Sbostic }
145152889Sbostic 
145252889Sbostic /* ARGSUSED */
145352889Sbostic static int
145452889Sbostic asc_sendsync(asc, status, ss, ir)
145552889Sbostic 	register asc_softc_t asc;
145652889Sbostic 	register int status, ss, ir;
145752889Sbostic {
145852889Sbostic 	register asc_regmap_t *regs = asc->regs;
145953080Sralph 	register State *state = &asc->st[asc->target];
146052889Sbostic 
146153080Sralph 	/* send the extended synchronous negotiation message */
146252889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
146352889Sbostic 	MachEmptyWriteBuffer();
146452889Sbostic 	regs->asc_fifo = 3;
146552889Sbostic 	MachEmptyWriteBuffer();
146652889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
146752889Sbostic 	MachEmptyWriteBuffer();
146852889Sbostic 	regs->asc_fifo = SCSI_MIN_PERIOD;
146952889Sbostic 	MachEmptyWriteBuffer();
147052889Sbostic 	regs->asc_fifo = ASC_MAX_OFFSET;
147153080Sralph 	/* state to resume after we see the sync reply message */
147253080Sralph 	state->script = asc->script + 2;
147353080Sralph 	state->msglen = 0;
147452889Sbostic 	return (1);
147552889Sbostic }
147652889Sbostic 
147752889Sbostic /* ARGSUSED */
147852889Sbostic static int
147952889Sbostic asc_replysync(asc, status, ss, ir)
148052889Sbostic 	register asc_softc_t asc;
148152889Sbostic 	register int status, ss, ir;
148252889Sbostic {
148352889Sbostic 	register asc_regmap_t *regs = asc->regs;
148452889Sbostic 	register State *state = &asc->st[asc->target];
148552889Sbostic 
148652889Sbostic #ifdef DEBUG
148752889Sbostic 	if (asc_debug > 2)
148852889Sbostic 		printf("asc_replysync: %x %x\n",
1489*56819Sralph 			asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
149052889Sbostic 			state->sync_offset);
149152889Sbostic #endif
149252889Sbostic 	/* send synchronous transfer in response to a request */
149352889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
149452889Sbostic 	MachEmptyWriteBuffer();
149552889Sbostic 	regs->asc_fifo = 3;
149652889Sbostic 	MachEmptyWriteBuffer();
149752889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
149852889Sbostic 	MachEmptyWriteBuffer();
1499*56819Sralph 	regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
150052889Sbostic 	MachEmptyWriteBuffer();
150152889Sbostic 	regs->asc_fifo = state->sync_offset;
150252889Sbostic 	regs->asc_cmd = ASC_CMD_XFER_INFO;
1503*56819Sralph 	readback(regs->asc_cmd);
150452889Sbostic 
150552889Sbostic 	/* return to the appropriate script */
150652889Sbostic 	if (!state->script) {
150752889Sbostic #ifdef DEBUG
150852889Sbostic 		asc_DumpLog("asc_replsync");
150952889Sbostic #endif
151052889Sbostic 		panic("asc_replysync");
151152889Sbostic 	}
151252889Sbostic 	asc->script = state->script;
151352889Sbostic 	state->script = (script_t *)0;
151452889Sbostic 	return (0);
151552889Sbostic }
151652889Sbostic 
151752889Sbostic /* ARGSUSED */
151852889Sbostic static int
151952942Sralph asc_msg_in(asc, status, ss, ir)
152052889Sbostic 	register asc_softc_t asc;
152152889Sbostic 	register int status, ss, ir;
152252889Sbostic {
152352889Sbostic 	register asc_regmap_t *regs = asc->regs;
152452889Sbostic 	register State *state = &asc->st[asc->target];
152552889Sbostic 	register int msg;
152652889Sbostic 	int i;
152752889Sbostic 
152852889Sbostic 	/* read one message byte */
152952889Sbostic 	msg = regs->asc_fifo;
153052889Sbostic #ifdef DEBUG
153152889Sbostic 	if (asc_logp == asc_log)
153252889Sbostic 		asc_log[NLOG - 1].msg = msg;
153352889Sbostic 	else
153452889Sbostic 		asc_logp[-1].msg = msg;
153552889Sbostic #endif
153652889Sbostic 
153752889Sbostic 	/* check for multi-byte message */
153852889Sbostic 	if (state->msglen != 0) {
153952889Sbostic 		/* first byte is the message length */
154052889Sbostic 		if (state->msglen < 0) {
154152889Sbostic 			state->msglen = msg;
154252889Sbostic 			return (1);
154352889Sbostic 		}
154452889Sbostic 		if (state->msgcnt >= state->msglen)
154552889Sbostic 			goto abort;
154652889Sbostic 		state->msg_in[state->msgcnt++] = msg;
154752889Sbostic 
154852889Sbostic 		/* did we just read the last byte of the message? */
154952889Sbostic 		if (state->msgcnt != state->msglen)
155052889Sbostic 			return (1);
155152889Sbostic 
155252889Sbostic 		/* process an extended message */
155352889Sbostic #ifdef DEBUG
155452889Sbostic 		if (asc_debug > 2)
155552942Sralph 			printf("asc_msg_in: msg %x %x %x\n",
155652889Sbostic 				state->msg_in[0],
155752889Sbostic 				state->msg_in[1],
155852889Sbostic 				state->msg_in[2]);
155952889Sbostic #endif
156052889Sbostic 		switch (state->msg_in[0]) {
156152889Sbostic 		case SCSI_SYNCHRONOUS_XFER:
156252889Sbostic 			state->flags |= DID_SYNC;
156352889Sbostic 			state->sync_offset = state->msg_in[2];
156452889Sbostic 
156552889Sbostic 			/* convert SCSI period to ASC period */
1566*56819Sralph 			i = state->msg_in[1] / asc->tb_ticks;
1567*56819Sralph 			if (i < asc->min_period)
1568*56819Sralph 				i = asc->min_period;
1569*56819Sralph 			else if (i >= asc->max_period) {
157052889Sbostic 				/* can't do sync transfer, period too long */
157152889Sbostic 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
157252889Sbostic 					asc - asc_softc, asc->target, i);
1573*56819Sralph 				i = asc->max_period;
157452889Sbostic 				state->sync_offset = 0;
157552889Sbostic 			}
1576*56819Sralph 			if ((i * asc->tb_ticks) != state->msg_in[1])
157752889Sbostic 				i++;
157852889Sbostic 			state->sync_period = i & 0x1F;
157952889Sbostic 
158052889Sbostic 			/*
158152889Sbostic 			 * If this is a request, check minimums and
158252889Sbostic 			 * send back an acknowledge.
158352889Sbostic 			 */
158452889Sbostic 			if (!(state->flags & TRY_SYNC)) {
158552889Sbostic 				regs->asc_cmd = ASC_CMD_SET_ATN;
1586*56819Sralph 				readback(regs->asc_cmd);
158752889Sbostic 				MachEmptyWriteBuffer();
158852889Sbostic 
1589*56819Sralph 				if (state->sync_period < asc->min_period)
159052889Sbostic 					state->sync_period =
1591*56819Sralph 						asc->min_period;
159252889Sbostic 				if (state->sync_offset > ASC_MAX_OFFSET)
159352889Sbostic 					state->sync_offset =
159452889Sbostic 						ASC_MAX_OFFSET;
159552889Sbostic 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
159652889Sbostic 				regs->asc_syn_p = state->sync_period;
1597*56819Sralph 				readback(regs->asc_syn_p);
159852889Sbostic 				regs->asc_syn_o = state->sync_offset;
1599*56819Sralph 				readback(regs->asc_syn_o);
160052889Sbostic 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
1601*56819Sralph 				readback(regs->asc_cmd);
160252889Sbostic 				return (0);
160352889Sbostic 			}
160452889Sbostic 
160552889Sbostic 			regs->asc_syn_p = state->sync_period;
1606*56819Sralph 			readback(regs->asc_syn_p);
160752889Sbostic 			regs->asc_syn_o = state->sync_offset;
1608*56819Sralph 			readback(regs->asc_syn_o);
160952889Sbostic 			goto done;
161052889Sbostic 
161152889Sbostic 		default:
161252889Sbostic 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
161352889Sbostic 				asc - asc_softc, asc->target,
161452889Sbostic 				state->msg_in[0]);
161552889Sbostic 			goto reject;
161652889Sbostic 		}
161752889Sbostic 	}
161852889Sbostic 
161952889Sbostic 	/* process first byte of a message */
162052889Sbostic #ifdef DEBUG
162152889Sbostic 	if (asc_debug > 2)
162252942Sralph 		printf("asc_msg_in: msg %x\n", msg);
162352889Sbostic #endif
162452889Sbostic 	switch (msg) {
162552889Sbostic #if 0
162652889Sbostic 	case SCSI_MESSAGE_REJECT:
162752889Sbostic 		printf(" did not like SYNCH xfer "); /* XXX */
162852889Sbostic 		state->flags |= DID_SYNC;
162952889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1630*56819Sralph 		readback(regs->asc_cmd);
163152889Sbostic 		status = asc_wait(regs, ASC_CSR_INT);
163252889Sbostic 		ir = regs->asc_intr;
163352889Sbostic 		/* some just break out here, some dont */
163452889Sbostic 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
163552889Sbostic 			regs->asc_fifo = SCSI_ABORT;
163652889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
1637*56819Sralph 			readback(regs->asc_cmd);
163852889Sbostic 			status = asc_wait(regs, ASC_CSR_INT);
163952889Sbostic 			ir = regs->asc_intr;
164052889Sbostic 		}
164152889Sbostic 		if (ir & ASC_INT_DISC) {
164252889Sbostic 			asc_end(asc, status, 0, ir);
164352889Sbostic 			return (0);
164452889Sbostic 		}
164552889Sbostic 		goto status;
164652889Sbostic #endif
164752889Sbostic 
164852889Sbostic 	case SCSI_EXTENDED_MSG: /* read an extended message */
164952889Sbostic 		/* setup to read message length next */
165052889Sbostic 		state->msglen = -1;
165152889Sbostic 		state->msgcnt = 0;
165252889Sbostic 		return (1);
165352889Sbostic 
165452889Sbostic 	case SCSI_NO_OP:
165552889Sbostic 		break;
165652889Sbostic 
165752889Sbostic 	case SCSI_SAVE_DATA_POINTER:
165852889Sbostic 		/* expect another message */
165952889Sbostic 		return (1);
166052889Sbostic 
166152889Sbostic 	case SCSI_RESTORE_POINTERS:
166252889Sbostic 		/*
166352889Sbostic 		 * Need to do the following if resuming synchonous data in
166452889Sbostic 		 * on an odd byte boundary.
166552889Sbostic 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
166652889Sbostic 		 */
166752889Sbostic 		break;
166852889Sbostic 
166952889Sbostic 	case SCSI_DISCONNECT:
167052889Sbostic 		if (state->flags & DISCONN)
167152889Sbostic 			goto abort;
167252889Sbostic 		state->flags |= DISCONN;
167352942Sralph 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1674*56819Sralph 		readback(regs->asc_cmd);
167552942Sralph 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
167652942Sralph 		return (0);
167752889Sbostic 
167852889Sbostic 	default:
167952889Sbostic 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
168052889Sbostic 			asc - asc_softc, asc->target, msg);
168152889Sbostic 	reject:
168252889Sbostic 		/* request a message out before acknowledging this message */
168352889Sbostic 		state->msg_out = SCSI_MESSAGE_REJECT;
168452889Sbostic 		regs->asc_cmd = ASC_CMD_SET_ATN;
1685*56819Sralph 		readback(regs->asc_cmd);
168652889Sbostic 		MachEmptyWriteBuffer();
168752889Sbostic 	}
168852889Sbostic 
168952889Sbostic done:
169052889Sbostic 	/* return to original script */
169152889Sbostic 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
1692*56819Sralph 	readback(regs->asc_cmd);
169352889Sbostic 	if (!state->script) {
169452889Sbostic 	abort:
169552889Sbostic #ifdef DEBUG
169652942Sralph 		asc_DumpLog("asc_msg_in");
169752889Sbostic #endif
169852942Sralph 		panic("asc_msg_in");
169952889Sbostic 	}
170052889Sbostic 	asc->script = state->script;
170152889Sbostic 	state->script = (script_t *)0;
170252889Sbostic 	return (0);
170352889Sbostic }
170452889Sbostic 
170552942Sralph /* ARGSUSED */
170652942Sralph static int
170752942Sralph asc_disconnect(asc, status, ss, ir)
170852942Sralph 	register asc_softc_t asc;
170952942Sralph 	register int status, ss, ir;
171052942Sralph {
171152942Sralph 	register State *state = &asc->st[asc->target];
171252942Sralph 
171352942Sralph 	asc->target = -1;
171452942Sralph 	asc->state = ASC_STATE_RESEL;
171552942Sralph 	return (1);
171652942Sralph }
171752942Sralph 
1718*56819Sralph /*
1719*56819Sralph  * DMA handling routines. For a turbochannel device, just set the dmar
1720*56819Sralph  * for the I/O ASIC, handle the actual DMA interface.
1721*56819Sralph  */
1722*56819Sralph static void
1723*56819Sralph tb_dma_start(asc, state, cp, flag)
1724*56819Sralph 	asc_softc_t asc;
1725*56819Sralph 	State *state;
1726*56819Sralph 	caddr_t cp;
1727*56819Sralph 	int flag;
1728*56819Sralph {
1729*56819Sralph 
1730*56819Sralph 	if (flag == ASCDMA_WRITE)
1731*56819Sralph 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
1732*56819Sralph 	else
1733*56819Sralph 		*asc->dmar = ASC_DMA_ADDR(cp);
1734*56819Sralph }
1735*56819Sralph 
1736*56819Sralph static void
1737*56819Sralph tb_dma_end(asc, state, flag)
1738*56819Sralph 	asc_softc_t asc;
1739*56819Sralph 	State *state;
1740*56819Sralph 	int flag;
1741*56819Sralph {
1742*56819Sralph 
1743*56819Sralph }
1744*56819Sralph 
1745*56819Sralph static void
1746*56819Sralph asic_dma_start(asc, state, cp, flag)
1747*56819Sralph 	asc_softc_t asc;
1748*56819Sralph 	State *state;
1749*56819Sralph 	caddr_t cp;
1750*56819Sralph 	int flag;
1751*56819Sralph {
1752*56819Sralph 	register volatile u_int *ssr = (volatile u_int *)
1753*56819Sralph 		MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR);
1754*56819Sralph 	u_int phys, nphys;
1755*56819Sralph 
1756*56819Sralph 	/* stop DMA engine first */
1757*56819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1758*56819Sralph 	* ((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR)) = 0;
1759*56819Sralph 
1760*56819Sralph 	phys = MACH_CACHED_TO_PHYS(cp);
1761*56819Sralph 	cp = (caddr_t)pmax_trunc_page(cp + NBPG);
1762*56819Sralph 	nphys = MACH_CACHED_TO_PHYS(cp);
1763*56819Sralph 
1764*56819Sralph 	asc->dma_next = cp;
1765*56819Sralph 	asc->dma_xfer = state->dmalen - (nphys - phys);
1766*56819Sralph 
1767*56819Sralph 	*(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR) =
1768*56819Sralph 		ASIC_DMA_ADDR(phys);
1769*56819Sralph 	*(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR) =
1770*56819Sralph 		ASIC_DMA_ADDR(nphys);
1771*56819Sralph 	if (flag == ASCDMA_READ)
1772*56819Sralph 		*ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI;
1773*56819Sralph 	else
1774*56819Sralph 		*ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI;
1775*56819Sralph 	MachEmptyWriteBuffer();
1776*56819Sralph }
1777*56819Sralph 
1778*56819Sralph static void
1779*56819Sralph asic_dma_end(asc, state, flag)
1780*56819Sralph 	asc_softc_t asc;
1781*56819Sralph 	State *state;
1782*56819Sralph 	int flag;
1783*56819Sralph {
1784*56819Sralph 	register volatile u_int *ssr = (volatile u_int *)
1785*56819Sralph 		MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR);
1786*56819Sralph 	int nb;
1787*56819Sralph 
1788*56819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1789*56819Sralph 	*((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR)) = -1;
1790*56819Sralph 	*((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR)) = -1;
1791*56819Sralph 	MachEmptyWriteBuffer();
1792*56819Sralph 
1793*56819Sralph 	if (flag == ASCDMA_READ) {
1794*56819Sralph 		MachFlushDCache(MACH_PHYS_TO_CACHED(
1795*56819Sralph 		    MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
1796*56819Sralph 		if (nb = *((int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR))) {
1797*56819Sralph 			/* pick up last upto6 bytes, sigh. */
1798*56819Sralph 			register u_short *to;
1799*56819Sralph 			register int w;
1800*56819Sralph 
1801*56819Sralph 			/* Last byte really xferred is.. */
1802*56819Sralph 			to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1));
1803*56819Sralph 			w = *(int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SDR0);
1804*56819Sralph 			*to++ = w;
1805*56819Sralph 			if (--nb > 0) {
1806*56819Sralph 				w >>= 16;
1807*56819Sralph 				*to++ = w;
1808*56819Sralph 			}
1809*56819Sralph 			if (--nb > 0) {
1810*56819Sralph 				w = *(int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SDR1);
1811*56819Sralph 				*to++ = w;
1812*56819Sralph 			}
1813*56819Sralph 		}
1814*56819Sralph 	}
1815*56819Sralph }
1816*56819Sralph 
1817*56819Sralph /*
1818*56819Sralph  * Called by asic_intr() for scsi dma pointer update interrupts.
1819*56819Sralph  */
1820*56819Sralph void
1821*56819Sralph asc_dma_intr()
1822*56819Sralph {
1823*56819Sralph 	asc_softc_t asc = &asc_softc[0];
1824*56819Sralph 	u_int next_phys;
1825*56819Sralph 
1826*56819Sralph 	asc->dma_xfer -= NBPG;
1827*56819Sralph 	if (asc->dma_xfer <= -NBPG) {
1828*56819Sralph 		volatile u_int *ssr = (volatile u_int *)
1829*56819Sralph 			MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR);
1830*56819Sralph 		*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1831*56819Sralph 	} else {
1832*56819Sralph 		asc->dma_next += NBPG;
1833*56819Sralph 		next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
1834*56819Sralph 	}
1835*56819Sralph #ifdef notdef
1836*56819Sralph 	else
1837*56819Sralph 		next_phys = MACH_CACHED_TO_PHYS(asc_iobuf);
1838*56819Sralph #endif
1839*56819Sralph 	*(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR) =
1840*56819Sralph 		ASIC_DMA_ADDR(next_phys);
1841*56819Sralph 	MachEmptyWriteBuffer();
1842*56819Sralph }
1843*56819Sralph 
184452889Sbostic #ifdef DEBUG
184552889Sbostic asc_DumpLog(str)
184652889Sbostic 	char *str;
184752889Sbostic {
184852889Sbostic 	register struct asc_log *lp;
184952889Sbostic 	register u_int status;
185052889Sbostic 
185152889Sbostic 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
185252889Sbostic 		asc_debug_bn, asc_debug_sz);
185352889Sbostic 	lp = asc_logp + 1;
185452889Sbostic 	if (lp > &asc_log[NLOG])
185552889Sbostic 		lp = asc_log;
185652889Sbostic 	while (lp != asc_logp) {
185752889Sbostic 		status = lp->status;
185852889Sbostic 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
185952889Sbostic 			status >> 24,
186052889Sbostic 			lp->target,
186152889Sbostic 			(status >> 16) & 0xFF,
186252889Sbostic 			(status >> 8) & 0xFF,
186352889Sbostic 			status & 0XFF,
186452889Sbostic 			lp->state,
186552889Sbostic 			asc_scripts[lp->state].condition,
186652889Sbostic 			lp->msg);
186752889Sbostic 		if (++lp >= &asc_log[NLOG])
186852889Sbostic 			lp = asc_log;
186952889Sbostic 	}
187052889Sbostic }
187152889Sbostic #endif
187252889Sbostic 
187352889Sbostic #endif	/* NASC > 0 */
1874