xref: /csrg-svn/sys/pmax/dev/asc.c (revision 67476)
152889Sbostic /*-
263205Sbostic  * Copyright (c) 1992, 1993
363205Sbostic  *	The Regents of the University of California.  All rights reserved.
452889Sbostic  *
552889Sbostic  * This code is derived from software contributed to Berkeley by
656819Sralph  * Ralph Campbell and Rick Macklem.
752889Sbostic  *
852889Sbostic  * %sccs.include.redist.c%
952889Sbostic  *
10*67476Smckusick  *	@(#)asc.c	8.3 (Berkeley) 07/03/94
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 
9456819Sralph #include <asc.h>
9552889Sbostic #if NASC > 0
9652889Sbostic 
9756522Sbostic #include <sys/param.h>
9856522Sbostic #include <sys/systm.h>
9956819Sralph #include <sys/dkstat.h>
10056819Sralph #include <sys/buf.h>
10156819Sralph #include <sys/conf.h>
10256522Sbostic #include <sys/errno.h>
10352889Sbostic 
10456819Sralph #include <machine/machConst.h>
10556819Sralph 
10656525Sbostic #include <pmax/dev/device.h>
10756525Sbostic #include <pmax/dev/scsi.h>
10856525Sbostic #include <pmax/dev/ascreg.h>
10952889Sbostic 
11056819Sralph #include <pmax/pmax/asic.h>
11156819Sralph #include <pmax/pmax/kmin.h>
11256819Sralph #include <pmax/pmax/pmaxtype.h>
11356819Sralph 
11456819Sralph #define	readback(a)	{ register int foo; foo = (a); }
11556819Sralph extern int pmax_boardtype;
11656819Sralph 
11756819Sralph /*
11856819Sralph  * In 4ns ticks.
11956819Sralph  */
12052889Sbostic int	asc_to_scsi_period[] = {
12156819Sralph 	32,
12256819Sralph 	33,
12356819Sralph 	34,
12456819Sralph 	35,
12556819Sralph 	5,
12656819Sralph 	5,
12756819Sralph 	6,
12856819Sralph 	7,
12956819Sralph 	8,
13056819Sralph 	9,
13156819Sralph 	10,
13256819Sralph 	11,
13356819Sralph 	12,
13456819Sralph 	13,
13556819Sralph 	14,
13656819Sralph 	15,
13756819Sralph 	16,
13856819Sralph 	17,
13956819Sralph 	18,
14056819Sralph 	19,
14156819Sralph 	20,
14256819Sralph 	21,
14356819Sralph 	22,
14456819Sralph 	23,
14556819Sralph 	24,
14656819Sralph 	25,
14756819Sralph 	26,
14856819Sralph 	27,
14956819Sralph 	28,
15056819Sralph 	29,
15156819Sralph 	30,
15256819Sralph 	31,
15352889Sbostic };
15452889Sbostic 
15552889Sbostic /*
15652889Sbostic  * Internal forward declarations.
15752889Sbostic  */
15852889Sbostic static void asc_reset();
15952889Sbostic static void asc_startcmd();
16052889Sbostic 
16152889Sbostic #ifdef DEBUG
16252889Sbostic int	asc_debug = 1;
16352889Sbostic int	asc_debug_cmd;
16452889Sbostic int	asc_debug_bn;
16552889Sbostic int	asc_debug_sz;
16658658Sralph #define NLOG 32
16752889Sbostic struct asc_log {
16852889Sbostic 	u_int	status;
16952889Sbostic 	u_char	state;
17052889Sbostic 	u_char	msg;
17152889Sbostic 	int	target;
17258658Sralph 	int	resid;
17352889Sbostic } asc_log[NLOG], *asc_logp = asc_log;
17452889Sbostic #define PACK(unit, status, ss, ir) \
17552889Sbostic 	((unit << 24) | (status << 16) | (ss << 8) | ir)
17652889Sbostic #endif
17752889Sbostic 
17852889Sbostic /*
17952889Sbostic  * Scripts are entries in a state machine table.
18052889Sbostic  * A script has four parts: a pre-condition, an action, a command to the chip,
18152889Sbostic  * and an index into asc_scripts for the next state. The first triggers error
18252889Sbostic  * handling if not satisfied and in our case it is formed by the
18352889Sbostic  * values of the interrupt register and status register, this
18452889Sbostic  * basically captures the phase of the bus and the TC and BS
18552889Sbostic  * bits.  The action part is just a function pointer, and the
18652889Sbostic  * command is what the 53C94 should be told to do at the end
18752889Sbostic  * of the action processing.  This command is only issued and the
18852889Sbostic  * script proceeds if the action routine returns TRUE.
18952889Sbostic  * See asc_intr() for how and where this is all done.
19052889Sbostic  */
19152889Sbostic typedef struct script {
19252889Sbostic 	int		condition;	/* expected state at interrupt time */
19352889Sbostic 	int		(*action)();	/* extra operations */
19452889Sbostic 	int		command;	/* command to the chip */
19552889Sbostic 	struct script	*next;		/* index into asc_scripts for next state */
19652889Sbostic } script_t;
19752889Sbostic 
19852889Sbostic /* Matching on the condition value */
19958658Sralph #define	SCRIPT_MATCH(ir, csr)		((ir) | (((csr) & 0x67) << 8))
20052889Sbostic 
20152889Sbostic /* forward decls of script actions */
20256819Sralph static int script_nop();		/* when nothing needed */
20356819Sralph static int asc_end();			/* all come to an end */
20456819Sralph static int asc_get_status();		/* get status from target */
20556819Sralph static int asc_dma_in();		/* start reading data from target */
20656819Sralph static int asc_last_dma_in();		/* cleanup after all data is read */
20756819Sralph static int asc_resume_in();		/* resume data in after a message */
20856819Sralph static int asc_resume_dma_in();		/* resume DMA after a disconnect */
20956819Sralph static int asc_dma_out();		/* send data to target via dma */
21056819Sralph static int asc_last_dma_out();		/* cleanup after all data is written */
21156819Sralph static int asc_resume_out();		/* resume data out after a message */
21256819Sralph static int asc_resume_dma_out();	/* resume DMA after a disconnect */
21356819Sralph static int asc_sendsync();		/* negotiate sync xfer */
21456819Sralph static int asc_replysync();		/* negotiate sync xfer */
21556819Sralph static int asc_msg_in();		/* process a message byte */
21656819Sralph static int asc_disconnect();		/* process an expected disconnect */
21752889Sbostic 
21852889Sbostic /* Define the index into asc_scripts for various state transitions */
21952889Sbostic #define	SCRIPT_DATA_IN		0
22052942Sralph #define	SCRIPT_CONTINUE_IN	2
22152942Sralph #define	SCRIPT_DATA_OUT		3
22252942Sralph #define	SCRIPT_CONTINUE_OUT	5
22352942Sralph #define	SCRIPT_SIMPLE		6
22452942Sralph #define	SCRIPT_GET_STATUS	7
22552942Sralph #define	SCRIPT_MSG_IN		9
22652942Sralph #define	SCRIPT_REPLY_SYNC	11
22752889Sbostic #define	SCRIPT_TRY_SYNC		12
22852942Sralph #define	SCRIPT_DISCONNECT	15
22952942Sralph #define	SCRIPT_RESEL		16
23052942Sralph #define	SCRIPT_RESUME_IN	17
23152942Sralph #define	SCRIPT_RESUME_DMA_IN	18
23252942Sralph #define	SCRIPT_RESUME_OUT	19
23352942Sralph #define	SCRIPT_RESUME_DMA_OUT	20
23452942Sralph #define	SCRIPT_RESUME_NO_DATA	21
23552889Sbostic 
23652889Sbostic /*
23752889Sbostic  * Scripts
23852889Sbostic  */
23952889Sbostic script_t asc_scripts[] = {
24052942Sralph 	/* start data in */
24152889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
24252889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
24352942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
24452889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
24552889Sbostic 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
24652942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
24752889Sbostic 
24858570Sralph 	/* continue data in after a chunk is finished */
24952942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/*  2 */
25052942Sralph 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
25152942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
25252942Sralph 
25352942Sralph 	/* start data out */
25452942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  3 */
25552889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
25652942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
25752942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  4 */
25852889Sbostic 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
25952942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
26052889Sbostic 
26158570Sralph 	/* continue data out after a chunk is finished */
26252942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/*  5 */
26352942Sralph 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
26452942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
26552942Sralph 
26652889Sbostic 	/* simple command with no data transfer */
26752942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  6 */
26852889Sbostic 		script_nop, ASC_CMD_I_COMPLETE,
26952942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
27052889Sbostic 
27152889Sbostic 	/* get status and finish command */
27252942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
27352889Sbostic 		asc_get_status, ASC_CMD_MSG_ACPT,
27452942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
27552942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  8 */
27652889Sbostic 		asc_end, ASC_CMD_NOP,
27752942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
27852889Sbostic 
27952889Sbostic 	/* message in */
28052942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  9 */
28152942Sralph 		asc_msg_in, ASC_CMD_MSG_ACPT,
28252942Sralph 		&asc_scripts[SCRIPT_MSG_IN + 1]},
28352942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 10 */
28452889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
28552942Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
28652889Sbostic 
28752889Sbostic 	/* send synchonous negotiation reply */
28852942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/* 11 */
28952889Sbostic 		asc_replysync, ASC_CMD_XFER_INFO,
29052942Sralph 		&asc_scripts[SCRIPT_REPLY_SYNC]},
29152889Sbostic 
29252889Sbostic 	/* try to negotiate synchonous transfer parameters */
29352889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
29452889Sbostic 		asc_sendsync, ASC_CMD_XFER_INFO,
29553080Sralph 		&asc_scripts[SCRIPT_TRY_SYNC + 1]},
29653080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 13 */
29752889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
29853080Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
29953080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND),			/* 14 */
30053080Sralph 		script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
30153080Sralph 		&asc_scripts[SCRIPT_RESUME_NO_DATA]},
30252889Sbostic 
30352942Sralph 	/* handle a disconnect */
30452942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO),			/* 15 */
30552942Sralph 		asc_disconnect, ASC_CMD_ENABLE_SEL,
30652942Sralph 		&asc_scripts[SCRIPT_RESEL]},
30752942Sralph 
30852889Sbostic 	/* reselect sequence: this is just a placeholder so match fails */
30952942Sralph 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 16 */
31052889Sbostic 		script_nop, ASC_CMD_MSG_ACPT,
31152942Sralph 		&asc_scripts[SCRIPT_RESEL]},
31252889Sbostic 
31352942Sralph 	/* resume data in after a message */
31452942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 17 */
31552942Sralph 		asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
31652942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
31752942Sralph 
31852942Sralph 	/* resume partial DMA data in after a message */
31952942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 18 */
32052889Sbostic 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
32152942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
32252889Sbostic 
32352942Sralph 	/* resume data out after a message */
32452942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 19 */
32552942Sralph 		asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
32652942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
32752942Sralph 
32852942Sralph 	/* resume partial DMA data out after a message */
32952942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 20 */
33052889Sbostic 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
33152942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
33252942Sralph 
33352942Sralph 	/* resume after a message when there is no more data */
33452942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/* 21 */
33552942Sralph 		script_nop, ASC_CMD_I_COMPLETE,
33652942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
33752889Sbostic };
33852889Sbostic 
33952889Sbostic /*
34052889Sbostic  * State kept for each active SCSI device.
34152889Sbostic  */
34252889Sbostic typedef struct scsi_state {
34352889Sbostic 	script_t *script;	/* saved script while processing error */
34452889Sbostic 	int	statusByte;	/* status byte returned during STATUS_PHASE */
34552889Sbostic 	int	error;		/* errno to pass back to device driver */
34652889Sbostic 	u_char	*dmaBufAddr;	/* DMA buffer address */
34752889Sbostic 	u_int	dmaBufSize;	/* DMA buffer size */
34852889Sbostic 	int	dmalen;		/* amount to transfer in this chunk */
34952889Sbostic 	int	dmaresid;	/* amount not transfered if chunk suspended */
35052889Sbostic 	int	buflen;		/* total remaining amount of data to transfer */
35152889Sbostic 	char	*buf;		/* current pointer within scsicmd->buf */
35252889Sbostic 	int	flags;		/* see below */
35352889Sbostic 	int	msglen;		/* number of message bytes to read */
35452889Sbostic 	int	msgcnt;		/* number of message bytes received */
35552889Sbostic 	u_char	sync_period;	/* DMA synchronous period */
35652889Sbostic 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
35752889Sbostic 	u_char	msg_out;	/* next MSG_OUT byte to send */
35852889Sbostic 	u_char	msg_in[16];	/* buffer for multibyte messages */
35952889Sbostic } State;
36052889Sbostic 
36152889Sbostic /* state flags */
36252889Sbostic #define DISCONN		0x01	/* true if currently disconnected from bus */
36353080Sralph #define DMA_IN_PROGRESS	0x02	/* true if data DMA started */
36452889Sbostic #define DMA_IN		0x04	/* true if reading from SCSI device */
36552889Sbostic #define DMA_OUT		0x10	/* true if writing to SCSI device */
36652889Sbostic #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
36752889Sbostic #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
36858658Sralph #define PARITY_ERR	0x80	/* true if parity error seen */
36952889Sbostic 
37052889Sbostic /*
37152889Sbostic  * State kept for each active SCSI host interface (53C94).
37252889Sbostic  */
37352889Sbostic struct asc_softc {
37452889Sbostic 	asc_regmap_t	*regs;		/* chip address */
37552889Sbostic 	volatile int	*dmar;		/* DMA address register address */
37656819Sralph 	u_char		*buff;		/* RAM buffer address (uncached) */
37752889Sbostic 	int		myid;		/* SCSI ID of this interface */
37852889Sbostic 	int		myidmask;	/* ~(1 << myid) */
37952889Sbostic 	int		state;		/* current SCSI connection state */
38052889Sbostic 	int		target;		/* target SCSI ID if busy */
38152889Sbostic 	script_t	*script;	/* next expected interrupt & action */
38252889Sbostic 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
38352889Sbostic 	State		st[ASC_NCMD];	/* state info for each active command */
38456819Sralph 	void		(*dma_start)();	/* Start dma routine */
38556819Sralph 	void		(*dma_end)();	/* End dma routine */
38656819Sralph 	u_char		*dma_next;
38756819Sralph 	int		dma_xfer;	/* Dma len still to go */
38856819Sralph 	int		min_period;	/* Min transfer period clk/byte */
38956819Sralph 	int		max_period;	/* Max transfer period clk/byte */
39056819Sralph 	int		ccf;		/* CCF, whatever that really is? */
39156819Sralph 	int		timeout_250;	/* 250ms timeout */
39256819Sralph 	int		tb_ticks;	/* 4ns. ticks/tb channel ticks */
39352889Sbostic } asc_softc[NASC];
39452889Sbostic 
39552889Sbostic #define	ASC_STATE_IDLE		0	/* idle state */
39652889Sbostic #define	ASC_STATE_BUSY		1	/* selecting or currently connected */
39752889Sbostic #define ASC_STATE_TARGET	2	/* currently selected as target */
39852889Sbostic #define ASC_STATE_RESEL		3	/* currently waiting for reselect */
39952889Sbostic 
40052889Sbostic typedef struct asc_softc *asc_softc_t;
40152889Sbostic 
40252889Sbostic /*
40356819Sralph  * Dma operations.
40456819Sralph  */
40556819Sralph #define	ASCDMA_READ	1
40656819Sralph #define	ASCDMA_WRITE	2
40756819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();
40857233Sralph extern u_long asc_iomem;
40957233Sralph extern u_long asic_base;
41056819Sralph 
41156819Sralph /*
41252889Sbostic  * Definition of the controller for the auto-configuration program.
41352889Sbostic  */
41452889Sbostic int	asc_probe();
41552889Sbostic void	asc_start();
41652889Sbostic void	asc_intr();
41752889Sbostic struct	driver ascdriver = {
41852889Sbostic 	"asc", asc_probe, asc_start, 0, asc_intr,
41952889Sbostic };
42052889Sbostic 
42152889Sbostic /*
42252889Sbostic  * Test to see if device is present.
42352889Sbostic  * Return true if found and initialized ok.
42452889Sbostic  */
42552889Sbostic asc_probe(cp)
42652889Sbostic 	register struct pmax_ctlr *cp;
42752889Sbostic {
42852889Sbostic 	register asc_softc_t asc;
42952889Sbostic 	register asc_regmap_t *regs;
43052889Sbostic 	int unit, id, s, i;
43157233Sralph 	int bufsiz;
43252889Sbostic 
43352889Sbostic 	if ((unit = cp->pmax_unit) >= NASC)
43452889Sbostic 		return (0);
43552889Sbostic 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
43652889Sbostic 		return (0);
43752889Sbostic 	asc = &asc_softc[unit];
43852889Sbostic 
43952889Sbostic 	/*
44052889Sbostic 	 * Initialize hw descriptor, cache some pointers
44152889Sbostic 	 */
44252889Sbostic 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
44352889Sbostic 
44456819Sralph 	/*
44556819Sralph 	 * Set up machine dependencies.
44656819Sralph 	 * 1) how to do dma
44756819Sralph 	 * 2) timing based on turbochannel frequency
44856819Sralph 	 */
44956819Sralph 	switch (pmax_boardtype) {
45056819Sralph 	case DS_3MIN:
45156819Sralph 	case DS_MAXINE:
45257233Sralph 	case DS_3MAXPLUS:
45356819Sralph 	    if (unit == 0) {
45457233Sralph 		asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
45557233Sralph 		bufsiz = 8192;
45657233Sralph 		*((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1;
45757233Sralph 		*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
45857233Sralph 		*((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
45956819Sralph 		asc->dma_start = asic_dma_start;
46056819Sralph 		asc->dma_end = asic_dma_end;
46156819Sralph 		break;
46256819Sralph 	    }
46356819Sralph 	    /*
46456819Sralph 	     * Fall through for turbochannel option.
46556819Sralph 	     */
46656819Sralph 	case DS_3MAX:
46756819Sralph 	default:
46856819Sralph 	    asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
46956819Sralph 	    asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
47057233Sralph 	    bufsiz = PER_TGT_DMA_SIZE;
47156819Sralph 	    asc->dma_start = tb_dma_start;
47256819Sralph 	    asc->dma_end = tb_dma_end;
47356819Sralph 	};
47456819Sralph 	/*
47556819Sralph 	 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and
47656819Sralph 	 * maxine are 12.5Mhz.
47756819Sralph 	 */
47856819Sralph 	switch (pmax_boardtype) {
47956819Sralph 	case DS_3MAX:
48057233Sralph 	case DS_3MAXPLUS:
48156819Sralph 		asc->min_period = ASC_MIN_PERIOD25;
48256819Sralph 		asc->max_period = ASC_MAX_PERIOD25;
48356819Sralph 		asc->ccf = ASC_CCF(25);
48456819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);
48556819Sralph 		asc->tb_ticks = 10;
48656819Sralph 		break;
48756819Sralph 	case DS_3MIN:
48856819Sralph 	case DS_MAXINE:
48956819Sralph 	default:
49056819Sralph 		asc->min_period = ASC_MIN_PERIOD12;
49156819Sralph 		asc->max_period = ASC_MAX_PERIOD12;
49256819Sralph 		asc->ccf = ASC_CCF(13);
49356819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);
49456819Sralph 		asc->tb_ticks = 20;
49556819Sralph 		break;
49656819Sralph 	};
49756819Sralph 
49852889Sbostic 	asc->state = ASC_STATE_IDLE;
49952889Sbostic 	asc->target = -1;
50052889Sbostic 
50152889Sbostic 	regs = asc->regs;
50252889Sbostic 
50352889Sbostic 	/*
50452889Sbostic 	 * Reset chip, fully.  Note that interrupts are already enabled.
50552889Sbostic 	 */
50652889Sbostic 	s = splbio();
50752889Sbostic 
50852889Sbostic 	/* preserve our ID for now */
50952889Sbostic 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
51052889Sbostic 	asc->myidmask = ~(1 << asc->myid);
51152889Sbostic 
51252889Sbostic 	asc_reset(asc, regs);
51352889Sbostic 
51452889Sbostic 	/*
51552889Sbostic 	 * Our SCSI id on the bus.
51652889Sbostic 	 * The user can set this via the prom on 3maxen/pmaxen.
51752889Sbostic 	 * If this changes it is easy to fix: make a default that
51852889Sbostic 	 * can be changed as boot arg.
51952889Sbostic 	 */
52052889Sbostic #ifdef	unneeded
52152889Sbostic 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
52252889Sbostic 			      (scsi_initiator_id[unit] & 0x7);
52352889Sbostic #endif
52452889Sbostic 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
52552889Sbostic 	splx(s);
52652889Sbostic 
52752889Sbostic 	/*
52852889Sbostic 	 * Statically partition the DMA buffer between targets.
52952889Sbostic 	 * This way we will eventually be able to attach/detach
53052889Sbostic 	 * drives on-fly.  And 18k/target is plenty for normal use.
53152889Sbostic 	 */
53252889Sbostic 
53352889Sbostic 	/*
53452889Sbostic 	 * Give each target its own DMA buffer region.
53552889Sbostic 	 * We may want to try ping ponging buffers later.
53652889Sbostic 	 */
53752889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
53857233Sralph 		asc->st[i].dmaBufAddr = asc->buff + bufsiz * i;
53957233Sralph 		asc->st[i].dmaBufSize = bufsiz;
54052889Sbostic 	}
54152889Sbostic 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
54252889Sbostic 		unit, cp->pmax_addr, cp->pmax_pri, id);
54352889Sbostic 	return (1);
54452889Sbostic }
54552889Sbostic 
54652889Sbostic /*
54752889Sbostic  * Start activity on a SCSI device.
54852889Sbostic  * We maintain information on each device separately since devices can
54952889Sbostic  * connect/disconnect during an operation.
55052889Sbostic  */
55152889Sbostic void
55252889Sbostic asc_start(scsicmd)
55352889Sbostic 	register ScsiCmd *scsicmd;	/* command to start */
55452889Sbostic {
55552889Sbostic 	register struct scsi_device *sdp = scsicmd->sd;
55652889Sbostic 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
55752889Sbostic 	int s;
55852889Sbostic 
55952889Sbostic 	s = splbio();
56052889Sbostic 	/*
56152889Sbostic 	 * Check if another command is already in progress.
56252889Sbostic 	 * We may have to change this if we allow SCSI devices with
56352889Sbostic 	 * separate LUNs.
56452889Sbostic 	 */
56552889Sbostic 	if (asc->cmd[sdp->sd_drive]) {
56652889Sbostic 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
56752889Sbostic 			sdp->sd_driver->d_name);
56852889Sbostic 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
56952889Sbostic 			scsicmd->buflen, 0);
57052889Sbostic 		splx(s);
57152889Sbostic 	}
57252889Sbostic 	asc->cmd[sdp->sd_drive] = scsicmd;
57352889Sbostic 	asc_startcmd(asc, sdp->sd_drive);
57452889Sbostic 	splx(s);
57552889Sbostic }
57652889Sbostic 
57752889Sbostic static void
57852889Sbostic asc_reset(asc, regs)
57952889Sbostic 	asc_softc_t asc;
58052889Sbostic 	asc_regmap_t *regs;
58152889Sbostic {
58252889Sbostic 
58352889Sbostic 	/*
58452889Sbostic 	 * Reset chip and wait till done
58552889Sbostic 	 */
58652889Sbostic 	regs->asc_cmd = ASC_CMD_RESET;
58752889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
58852889Sbostic 
58952889Sbostic 	/* spec says this is needed after reset */
59052889Sbostic 	regs->asc_cmd = ASC_CMD_NOP;
59152889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
59252889Sbostic 
59352889Sbostic 	/*
59452889Sbostic 	 * Set up various chip parameters
59552889Sbostic 	 */
59656819Sralph 	regs->asc_ccf = asc->ccf;
59752889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
59856819Sralph 	regs->asc_sel_timo = asc->timeout_250;
59952889Sbostic 	/* restore our ID */
60052889Sbostic 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
60157233Sralph 	/* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
60257233Sralph 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
60352889Sbostic 	regs->asc_cnfg3 = 0;
60452889Sbostic 	/* zero anything else */
60552889Sbostic 	ASC_TC_PUT(regs, 0);
60656819Sralph 	regs->asc_syn_p = asc->min_period;
60752889Sbostic 	regs->asc_syn_o = 0;	/* async for now */
60852889Sbostic 	MachEmptyWriteBuffer();
60952889Sbostic }
61052889Sbostic 
61152889Sbostic /*
61252889Sbostic  * Start a SCSI command on a target.
61352889Sbostic  */
61452889Sbostic static void
61552889Sbostic asc_startcmd(asc, target)
61652889Sbostic 	asc_softc_t asc;
61752889Sbostic 	int target;
61852889Sbostic {
61952889Sbostic 	register asc_regmap_t *regs;
62052889Sbostic 	register ScsiCmd *scsicmd;
62152889Sbostic 	register State *state;
62252889Sbostic 	int len;
62352889Sbostic 
62452889Sbostic 	/*
62552889Sbostic 	 * See if another target is currently selected on this SCSI bus.
62652889Sbostic 	 */
62752889Sbostic 	if (asc->target >= 0)
62852889Sbostic 		return;
62952889Sbostic 
63052889Sbostic 	regs = asc->regs;
63152889Sbostic 
63252889Sbostic 	/*
63358658Sralph 	 * If a reselection is in progress, it is Ok to ignore it since
63458658Sralph 	 * the ASC will automatically cancel the command and flush
63558658Sralph 	 * the FIFO if the ASC is reselected before the command starts.
63658658Sralph 	 * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if
63758658Sralph 	 * a reselect occurs before starting the command.
63852889Sbostic 	 */
63952889Sbostic 
64052889Sbostic 	asc->state = ASC_STATE_BUSY;
64152889Sbostic 	asc->target = target;
64252889Sbostic 
64352889Sbostic 	/* cache some pointers */
64452889Sbostic 	scsicmd = asc->cmd[target];
64552889Sbostic 	state = &asc->st[target];
64652889Sbostic 
64752889Sbostic #ifdef DEBUG
64852889Sbostic 	if (asc_debug > 1) {
64952889Sbostic 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
65052889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
65152889Sbostic 			scsicmd->cmd[0], scsicmd->buflen);
65252889Sbostic 	}
65352889Sbostic #endif
65452889Sbostic 
65552889Sbostic 	/*
65652889Sbostic 	 * Init the chip and target state.
65752889Sbostic 	 */
65853080Sralph 	state->flags = state->flags & DID_SYNC;
65952889Sbostic 	state->error = 0;
66052889Sbostic 	state->script = (script_t *)0;
66152889Sbostic 	state->msg_out = SCSI_NO_OP;
66252889Sbostic 
66352889Sbostic 	/*
66452889Sbostic 	 * Copy command data to the DMA buffer.
66552889Sbostic 	 */
66660301Sralph 	len = scsicmd->cmdlen;
66752889Sbostic 	state->dmalen = len;
66860301Sralph 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
66952889Sbostic 
67052889Sbostic 	/* check for simple SCSI command with no data transfer */
67152889Sbostic 	if ((state->buflen = scsicmd->buflen) == 0) {
67252889Sbostic 		/* check for sync negotiation */
67352889Sbostic 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
67452889Sbostic 		    !(state->flags & DID_SYNC)) {
67552889Sbostic 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
67652889Sbostic 			state->flags |= TRY_SYNC;
67752889Sbostic 		} else
67852889Sbostic 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
67952889Sbostic 		state->buf = (char *)0;
68052889Sbostic 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
68152889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
68253080Sralph 		state->buf = scsicmd->buf;
68352889Sbostic 		state->flags |= DMA_OUT;
68452889Sbostic 	} else {
68552889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
68652889Sbostic 		state->buf = scsicmd->buf;
68752889Sbostic 		state->flags |= DMA_IN;
68852889Sbostic 	}
68952889Sbostic 
69058792Sralph #ifdef DEBUG
69158792Sralph 	asc_debug_cmd = scsicmd->cmd[0];
69258792Sralph 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
69358792Sralph 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
69458792Sralph 			(scsicmd->cmd[3] << 16) |
69558792Sralph 			(scsicmd->cmd[4] << 8) |
69658792Sralph 			scsicmd->cmd[5];
69758792Sralph 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
69858792Sralph 	}
69958792Sralph 	asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd);
70058792Sralph 	asc_logp->target = asc->target;
70158792Sralph 	asc_logp->state = asc->script - asc_scripts;
70258792Sralph 	asc_logp->msg = SCSI_DIS_REC_IDENTIFY;
70358792Sralph 	asc_logp->resid = scsicmd->buflen;
70458792Sralph 	if (++asc_logp >= &asc_log[NLOG])
70558792Sralph 		asc_logp = asc_log;
70658792Sralph #endif
70752889Sbostic 
70860301Sralph 	/* preload the FIFO with the message to be sent */
70960301Sralph 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
71060301Sralph 	MachEmptyWriteBuffer();
71160301Sralph 
71258792Sralph 	/* initialize the DMA */
71356819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
71452889Sbostic 	ASC_TC_PUT(regs, len);
71556819Sralph 	readback(regs->asc_cmd);
71652889Sbostic 
71752889Sbostic 	regs->asc_dbus_id = target;
71856819Sralph 	readback(regs->asc_dbus_id);
71952889Sbostic 	regs->asc_syn_p = state->sync_period;
72056819Sralph 	readback(regs->asc_syn_p);
72152889Sbostic 	regs->asc_syn_o = state->sync_offset;
72256819Sralph 	readback(regs->asc_syn_o);
72352889Sbostic 
72452889Sbostic 	if (state->flags & TRY_SYNC)
72553080Sralph 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
72652889Sbostic 	else
72752889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
72856819Sralph 	readback(regs->asc_cmd);
72952889Sbostic }
73052889Sbostic 
73152889Sbostic /*
73252889Sbostic  * Interrupt routine
73352889Sbostic  *	Take interrupts from the chip
73452889Sbostic  *
73552889Sbostic  * Implementation:
73652889Sbostic  *	Move along the current command's script if
73752889Sbostic  *	all is well, invoke error handler if not.
73852889Sbostic  */
73952889Sbostic void
74052889Sbostic asc_intr(unit)
74152889Sbostic 	int unit;
74252889Sbostic {
74352889Sbostic 	register asc_softc_t asc = &asc_softc[unit];
74452889Sbostic 	register asc_regmap_t *regs = asc->regs;
74552889Sbostic 	register State *state;
74652889Sbostic 	register script_t *scpt;
74752889Sbostic 	register int ss, ir, status;
74852889Sbostic 
74952889Sbostic 	/* collect ephemeral information */
75052889Sbostic 	status = regs->asc_status;
75153080Sralph again:
75252889Sbostic 	ss = regs->asc_ss;
75352889Sbostic 	ir = regs->asc_intr;	/* this resets the previous two */
75452889Sbostic 	scpt = asc->script;
75552889Sbostic 
75652889Sbostic #ifdef DEBUG
75752889Sbostic 	asc_logp->status = PACK(unit, status, ss, ir);
75852889Sbostic 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
75952889Sbostic 	asc_logp->state = scpt - asc_scripts;
76052889Sbostic 	asc_logp->msg = -1;
76158658Sralph 	asc_logp->resid = 0;
76252889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
76352889Sbostic 		asc_logp = asc_log;
76452889Sbostic 	if (asc_debug > 2)
76552889Sbostic 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
76652889Sbostic 			status, ss, ir, scpt - asc_scripts, scpt->condition);
76752889Sbostic #endif
76852889Sbostic 
76952889Sbostic 	/* check the expected state */
77052889Sbostic 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
77152889Sbostic 		/*
77252889Sbostic 		 * Perform the appropriate operation, then proceed.
77352889Sbostic 		 */
77452889Sbostic 		if ((*scpt->action)(asc, status, ss, ir)) {
77552889Sbostic 			regs->asc_cmd = scpt->command;
77656819Sralph 			readback(regs->asc_cmd);
77752889Sbostic 			asc->script = scpt->next;
77852889Sbostic 		}
77952889Sbostic 		goto done;
78052889Sbostic 	}
78152889Sbostic 
78258658Sralph 	/*
78358658Sralph 	 * Check for parity error.
78458658Sralph 	 * Hardware will automatically set ATN
78558658Sralph 	 * to request the device for a MSG_OUT phase.
78658658Sralph 	 */
78758658Sralph 	if (status & ASC_CSR_PE) {
78858658Sralph 		printf("asc%d: SCSI device %d: incomming parity error seen\n",
78958658Sralph 			asc - asc_softc, asc->target);
79058658Sralph 		asc->st[asc->target].flags |= PARITY_ERR;
79158658Sralph 	}
79258658Sralph 
79358658Sralph 	/*
79458658Sralph 	 * Check for gross error.
79558658Sralph 	 * Probably a bug in a device driver.
79658658Sralph 	 */
79758658Sralph 	if (status & ASC_CSR_GE) {
79858658Sralph 		printf("asc%d: SCSI device %d: gross error\n",
79958658Sralph 			asc - asc_softc, asc->target);
80058658Sralph 		goto abort;
80158658Sralph 	}
80258658Sralph 
80352889Sbostic 	/* check for message in or out */
80452889Sbostic 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
80552889Sbostic 		register int len, fifo;
80652889Sbostic 
80752889Sbostic 		state = &asc->st[asc->target];
80852889Sbostic 		switch (ASC_PHASE(status)) {
80953080Sralph 		case ASC_PHASE_DATAI:
81053080Sralph 		case ASC_PHASE_DATAO:
81153080Sralph 			ASC_TC_GET(regs, len);
81253080Sralph 			fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
81353080Sralph 			printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
81453080Sralph 				state->buflen, state->dmalen, len, fifo);
81553080Sralph 			goto abort;
81653080Sralph 
81752889Sbostic 		case ASC_PHASE_MSG_IN:
81852889Sbostic 			break;
81952889Sbostic 
82052889Sbostic 		case ASC_PHASE_MSG_OUT:
82158658Sralph 			/*
82258658Sralph 			 * Check for parity error.
82358658Sralph 			 * Hardware will automatically set ATN
82458658Sralph 			 * to request the device for a MSG_OUT phase.
82558658Sralph 			 */
82658658Sralph 			if (state->flags & PARITY_ERR) {
82758658Sralph 				state->flags &= ~PARITY_ERR;
82858658Sralph 				state->msg_out = SCSI_MESSAGE_PARITY_ERROR;
82958658Sralph 				/* reset message in counter */
83058658Sralph 				state->msglen = 0;
83158658Sralph 			} else
83258658Sralph 				state->msg_out = SCSI_NO_OP;
83352889Sbostic 			regs->asc_fifo = state->msg_out;
83452889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
83556819Sralph 			readback(regs->asc_cmd);
83652889Sbostic 			goto done;
83752889Sbostic 
83852889Sbostic 		case ASC_PHASE_STATUS:
83952889Sbostic 			/* probably an error in the SCSI command */
84052889Sbostic 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
84152889Sbostic 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
84256819Sralph 			readback(regs->asc_cmd);
84352889Sbostic 			goto done;
84452889Sbostic 
84552889Sbostic 		default:
84652889Sbostic 			goto abort;
84752889Sbostic 		}
84852889Sbostic 
84952889Sbostic 		if (state->script)
85052889Sbostic 			goto abort;
85152889Sbostic 
85252889Sbostic 		/* check for DMA in progress */
85352889Sbostic 		ASC_TC_GET(regs, len);
85452889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
85552889Sbostic 		/* flush any data in the FIFO */
85652889Sbostic 		if (fifo) {
85753080Sralph 			if (state->flags & DMA_OUT)
85853080Sralph 				len += fifo;
85953080Sralph 			else if (state->flags & DMA_IN) {
86053080Sralph 				u_char *cp;
86153080Sralph 
86253080Sralph 				printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
86353080Sralph 					state->dmalen, len, fifo); /* XXX */
86453080Sralph 				len += fifo;
86553080Sralph 				cp = state->dmaBufAddr + (state->dmalen - len);
86653080Sralph 				while (fifo-- > 0)
86753080Sralph 					*cp++ = regs->asc_fifo;
86853080Sralph 			} else
86953080Sralph 				printf("asc_intr: dmalen %d len %d fifo %d\n",
87053080Sralph 					state->dmalen, len, fifo); /* XXX */
87152889Sbostic 			regs->asc_cmd = ASC_CMD_FLUSH;
87256819Sralph 			readback(regs->asc_cmd);
87356819Sralph 			DELAY(2);
87452889Sbostic 		}
87565433Smckusick 		if (len && (state->flags & DMA_IN_PROGRESS)) {
87652889Sbostic 			/* save number of bytes still to be sent or received */
87752889Sbostic 			state->dmaresid = len;
87865433Smckusick 			state->flags &= ~DMA_IN_PROGRESS;
879*67476Smckusick 			ASC_TC_PUT(regs, 0);
88058792Sralph #ifdef DEBUG
88158792Sralph 			if (asc_logp == asc_log)
88258792Sralph 				asc_log[NLOG - 1].resid = len;
88358792Sralph 			else
88458792Sralph 				asc_logp[-1].resid = len;
88558792Sralph #endif
88652889Sbostic 			/* setup state to resume to */
88758792Sralph 			if (state->flags & DMA_IN) {
88858792Sralph 				/*
88958792Sralph 				 * Since the ASC_CNFG3_SRB bit of the
89058792Sralph 				 * cnfg3 register bit is not set,
89158792Sralph 				 * we just transferred an extra byte.
89258792Sralph 				 * Since we can't resume on an odd byte
89358792Sralph 				 * boundary, we copy the valid data out
89458792Sralph 				 * and resume DMA at the start address.
89558792Sralph 				 */
89658792Sralph 				if (len & 1) {
89758792Sralph 					printf("asc_intr: msg in len %d (fifo %d)\n",
89865433Smckusick 						len, fifo); /* XXX */
89958792Sralph 					len = state->dmalen - len;
90058792Sralph 					goto do_in;
90158792Sralph 				}
90252889Sbostic 				state->script =
90352889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
90458792Sralph 			} else if (state->flags & DMA_OUT)
90552889Sbostic 				state->script =
90652889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
90752889Sbostic 			else
90852889Sbostic 				state->script = asc->script;
90965433Smckusick 		} else if (state->flags & DMA_IN) {
910*67476Smckusick 			if (len) {
911*67476Smckusick 				printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
912*67476Smckusick 					asc_debug_bn, len, fifo); /* XXX */
913*67476Smckusick 				goto abort;
914*67476Smckusick 			}
91552889Sbostic 			/* setup state to resume to */
91665433Smckusick 			if (state->flags & DMA_IN_PROGRESS) {
91765433Smckusick 				len = state->dmalen;
91865433Smckusick 				state->flags &= ~DMA_IN_PROGRESS;
91965433Smckusick 			do_in:
92065433Smckusick 				(*asc->dma_end)(asc, state, ASCDMA_READ);
92165433Smckusick 				bcopy(state->dmaBufAddr, state->buf, len);
92265433Smckusick 				state->buf += len;
92365433Smckusick 				state->buflen -= len;
92465433Smckusick 			}
92565433Smckusick 			if (state->buflen)
92653080Sralph 				state->script =
92765433Smckusick 				    &asc_scripts[SCRIPT_RESUME_IN];
92853080Sralph 			else
92965433Smckusick 				state->script =
93065433Smckusick 				    &asc_scripts[SCRIPT_RESUME_NO_DATA];
93165433Smckusick 		} else if (state->flags & DMA_OUT) {
932*67476Smckusick 			if (len) {
93365433Smckusick 				printf("asc_intr: 2: len %d (fifo %d)\n", len,
93465433Smckusick 					fifo); /* XXX */
935*67476Smckusick 				goto abort;
936*67476Smckusick 			}
93765433Smckusick 			/*
93865433Smckusick 			 * If this is the last chunk, the next expected
93965433Smckusick 			 * state is to get status.
94065433Smckusick 			 */
94165433Smckusick 			if (state->flags & DMA_IN_PROGRESS) {
94265433Smckusick 				state->flags &= ~DMA_IN_PROGRESS;
94365433Smckusick 				(*asc->dma_end)(asc, state, ASCDMA_WRITE);
94465433Smckusick 				len = state->dmalen;
94565433Smckusick 				state->buf += len;
94665433Smckusick 				state->buflen -= len;
94765433Smckusick 			}
94865433Smckusick 			if (state->buflen)
94965433Smckusick 				state->script =
95065433Smckusick 				    &asc_scripts[SCRIPT_RESUME_OUT];
95165433Smckusick 			else
95265433Smckusick 				state->script =
95365433Smckusick 				    &asc_scripts[SCRIPT_RESUME_NO_DATA];
95465433Smckusick 		} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
95565433Smckusick 			state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];
95665433Smckusick 		else
95765433Smckusick 			state->script = asc->script;
95852889Sbostic 
95952889Sbostic 		/* setup to receive a message */
96052889Sbostic 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
96152889Sbostic 		state->msglen = 0;
96252889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO;
96356819Sralph 		readback(regs->asc_cmd);
96452889Sbostic 		goto done;
96552889Sbostic 	}
96652889Sbostic 
96752889Sbostic 	/* check for SCSI bus reset */
96852889Sbostic 	if (ir & ASC_INT_RESET) {
96952889Sbostic 		register int i;
97052889Sbostic 
97152889Sbostic 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
97252889Sbostic 		/* need to flush any pending commands */
97352889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
97452889Sbostic 			if (!asc->cmd[i])
97552889Sbostic 				continue;
97652889Sbostic 			asc->st[i].error = EIO;
97752889Sbostic 			asc_end(asc, 0, 0, 0);
97852889Sbostic 		}
97952889Sbostic 		/* rearbitrate synchronous offset */
98052889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
98152889Sbostic 			asc->st[i].sync_offset = 0;
98252889Sbostic 			asc->st[i].flags = 0;
98352889Sbostic 		}
98452889Sbostic 		asc->target = -1;
98552889Sbostic 		return;
98652889Sbostic 	}
98752889Sbostic 
98852889Sbostic 	/* check for command errors */
98952889Sbostic 	if (ir & ASC_INT_ILL)
99052889Sbostic 		goto abort;
99152889Sbostic 
99252889Sbostic 	/* check for disconnect */
99352889Sbostic 	if (ir & ASC_INT_DISC) {
99452889Sbostic 		state = &asc->st[asc->target];
99552889Sbostic 		switch (ASC_SS(ss)) {
99652889Sbostic 		case 0: /* device did not respond */
99758658Sralph 			/* check for one of the starting scripts */
99858658Sralph 			switch (asc->script - asc_scripts) {
99958658Sralph 			case SCRIPT_TRY_SYNC:
100058658Sralph 			case SCRIPT_SIMPLE:
100158658Sralph 			case SCRIPT_DATA_IN:
100258658Sralph 			case SCRIPT_DATA_OUT:
100358658Sralph 				if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {
100458658Sralph 					regs->asc_cmd = ASC_CMD_FLUSH;
100558658Sralph 					readback(regs->asc_cmd);
100658658Sralph 				}
100758658Sralph 				state->error = ENXIO;
100858658Sralph 				asc_end(asc, status, ss, ir);
100958658Sralph 				return;
101058658Sralph 			}
101158658Sralph 			/* FALLTHROUGH */
101252889Sbostic 
101352889Sbostic 		default:
101458658Sralph 			printf("asc%d: SCSI device %d: unexpected disconnect\n",
101558658Sralph 				asc - asc_softc, asc->target);
101657233Sralph 			/*
101757233Sralph 			 * On rare occasions my RZ24 does a disconnect during
101857233Sralph 			 * data in phase and the following seems to keep it
101957233Sralph 			 * happy.
102057233Sralph 			 * XXX Should a scsi disk ever do this??
102157233Sralph 			 */
102257233Sralph 			asc->script = &asc_scripts[SCRIPT_RESEL];
102357233Sralph 			asc->state = ASC_STATE_RESEL;
102457233Sralph 			state->flags |= DISCONN;
102557233Sralph 			regs->asc_cmd = ASC_CMD_ENABLE_SEL;
102657233Sralph 			readback(regs->asc_cmd);
102757233Sralph 			return;
102852889Sbostic 		}
102952889Sbostic 	}
103052889Sbostic 
103152889Sbostic 	/* check for reselect */
103252889Sbostic 	if (ir & ASC_INT_RESEL) {
103352889Sbostic 		unsigned fifo, id, msg;
103452889Sbostic 
103552889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
103652889Sbostic 		if (fifo < 2)
103752889Sbostic 			goto abort;
103852889Sbostic 		/* read unencoded SCSI ID and convert to binary */
103952889Sbostic 		msg = regs->asc_fifo & asc->myidmask;
104052889Sbostic 		for (id = 0; (msg & 1) == 0; id++)
104152889Sbostic 			msg >>= 1;
104252889Sbostic 		/* read identify message */
104352889Sbostic 		msg = regs->asc_fifo;
104452889Sbostic #ifdef DEBUG
104552889Sbostic 		if (asc_logp == asc_log)
104652889Sbostic 			asc_log[NLOG - 1].msg = msg;
104752889Sbostic 		else
104852889Sbostic 			asc_logp[-1].msg = msg;
104952889Sbostic #endif
105052889Sbostic 		asc->state = ASC_STATE_BUSY;
105152889Sbostic 		asc->target = id;
105252889Sbostic 		state = &asc->st[id];
105352889Sbostic 		asc->script = state->script;
105452889Sbostic 		state->script = (script_t *)0;
105552889Sbostic 		if (!(state->flags & DISCONN))
105652889Sbostic 			goto abort;
105752889Sbostic 		state->flags &= ~DISCONN;
105853080Sralph 		regs->asc_syn_p = state->sync_period;
105953080Sralph 		regs->asc_syn_o = state->sync_offset;
106052889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
106156819Sralph 		readback(regs->asc_cmd);
106252889Sbostic 		goto done;
106352889Sbostic 	}
106452889Sbostic 
106552889Sbostic 	/* check if we are being selected as a target */
106652889Sbostic 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
106752889Sbostic 		goto abort;
106852889Sbostic 
106958658Sralph 	/*
107058658Sralph 	 * 'ir' must be just ASC_INT_FC.
107158658Sralph 	 * This is normal if canceling an ASC_ENABLE_SEL.
107258658Sralph 	 */
107358658Sralph 
107452889Sbostic done:
107552889Sbostic 	MachEmptyWriteBuffer();
107653080Sralph 	/* watch out for HW race conditions and setup & hold time violations */
107753080Sralph 	ir = regs->asc_status;
107853080Sralph 	while (ir != (status = regs->asc_status))
107953080Sralph 		ir = status;
108053080Sralph 	if (status & ASC_CSR_INT)
108152889Sbostic 		goto again;
108252889Sbostic 	return;
108352889Sbostic 
108452889Sbostic abort:
108552889Sbostic #ifdef DEBUG
108652889Sbostic 	asc_DumpLog("asc_intr");
108752889Sbostic #endif
108852889Sbostic #if 0
108952889Sbostic 	panic("asc_intr");
109052889Sbostic #else
1091*67476Smckusick 	boot(4); /* XXX */
109252889Sbostic #endif
109352889Sbostic }
109452889Sbostic 
109552889Sbostic /*
109652889Sbostic  * All the many little things that the interrupt
109752889Sbostic  * routine might switch to.
109852889Sbostic  */
109952889Sbostic 
110052889Sbostic /* ARGSUSED */
110152889Sbostic static int
110252889Sbostic script_nop(asc, status, ss, ir)
110352889Sbostic 	register asc_softc_t asc;
110452889Sbostic 	register int status, ss, ir;
110552889Sbostic {
110652889Sbostic 	return (1);
110752889Sbostic }
110852889Sbostic 
110952889Sbostic /* ARGSUSED */
111052889Sbostic static int
111152889Sbostic asc_get_status(asc, status, ss, ir)
111252889Sbostic 	register asc_softc_t asc;
111352889Sbostic 	register int status, ss, ir;
111452889Sbostic {
111552889Sbostic 	register asc_regmap_t *regs = asc->regs;
111652889Sbostic 	register int data;
111752889Sbostic 
111852889Sbostic 	/*
111952889Sbostic 	 * Get the last two bytes in the FIFO.
112052889Sbostic 	 */
112152889Sbostic 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
112252889Sbostic 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
112358658Sralph 		asc_DumpLog("get_status"); /* XXX */
112452889Sbostic 		if (data < 2) {
112552889Sbostic 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
112656819Sralph 			readback(asc->regs->asc_cmd);
112752889Sbostic 			return (0);
112852889Sbostic 		}
112952889Sbostic 		do {
113052889Sbostic 			data = regs->asc_fifo;
113152889Sbostic 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
113252889Sbostic 	}
113352889Sbostic 
113452889Sbostic 	/* save the status byte */
113552889Sbostic 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
113652889Sbostic #ifdef DEBUG
113752889Sbostic 	if (asc_logp == asc_log)
113852889Sbostic 		asc_log[NLOG - 1].msg = data;
113952889Sbostic 	else
114052889Sbostic 		asc_logp[-1].msg = data;
114152889Sbostic #endif
114252889Sbostic 
114352889Sbostic 	/* get the (presumed) command_complete message */
114452889Sbostic 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
114552889Sbostic 		return (1);
114652889Sbostic 
114752889Sbostic #ifdef DEBUG
114852889Sbostic 	printf("asc_get_status: status %x cmd %x\n",
114952889Sbostic 		asc->st[asc->target].statusByte, data);
115052889Sbostic 	asc_DumpLog("asc_get_status");
115152889Sbostic #endif
115252889Sbostic 	return (0);
115352889Sbostic }
115452889Sbostic 
115552889Sbostic /* ARGSUSED */
115652889Sbostic static int
115752889Sbostic asc_end(asc, status, ss, ir)
115852889Sbostic 	register asc_softc_t asc;
115952889Sbostic 	register int status, ss, ir;
116052889Sbostic {
116152889Sbostic 	register ScsiCmd *scsicmd;
116252889Sbostic 	register State *state;
116352889Sbostic 	register int i, target;
116452889Sbostic 
116552889Sbostic 	asc->state = ASC_STATE_IDLE;
116652889Sbostic 	target = asc->target;
116752889Sbostic 	asc->target = -1;
116852889Sbostic 	scsicmd = asc->cmd[target];
116952889Sbostic 	asc->cmd[target] = (ScsiCmd *)0;
117052889Sbostic 	state = &asc->st[target];
117152889Sbostic 
117252889Sbostic #ifdef DEBUG
117352889Sbostic 	if (asc_debug > 1) {
117452889Sbostic 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
117552889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
117652889Sbostic 			scsicmd->cmd[0], state->error, state->buflen);
117752889Sbostic 	}
117852889Sbostic #endif
117952889Sbostic #ifdef DIAGNOSTIC
118052889Sbostic 	if (target < 0 || !scsicmd)
118152889Sbostic 		panic("asc_end");
118252889Sbostic #endif
118352889Sbostic 
118452889Sbostic 	/* look for disconnected devices */
118552889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
118652889Sbostic 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
118752889Sbostic 			continue;
118852889Sbostic 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
118956819Sralph 		readback(asc->regs->asc_cmd);
119052889Sbostic 		asc->state = ASC_STATE_RESEL;
119152889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESEL];
119252889Sbostic 		break;
119352889Sbostic 	}
119452889Sbostic 
119558658Sralph 	/*
119658658Sralph 	 * Look for another device that is ready.
119758658Sralph 	 * May want to keep last one started and increment for fairness
119858658Sralph 	 * rather than always starting at zero.
119958658Sralph 	 */
120052889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
120152889Sbostic 		/* don't restart a disconnected command */
120252889Sbostic 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
120352889Sbostic 			continue;
120452889Sbostic 		asc_startcmd(asc, i);
120552889Sbostic 		break;
120652889Sbostic 	}
120752889Sbostic 
120852889Sbostic 	/* signal device driver that the command is done */
120952889Sbostic 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
121052889Sbostic 		state->buflen, state->statusByte);
121152889Sbostic 
121252889Sbostic 	return (0);
121352889Sbostic }
121452889Sbostic 
121552889Sbostic /* ARGSUSED */
121652889Sbostic static int
121752889Sbostic asc_dma_in(asc, status, ss, ir)
121852889Sbostic 	register asc_softc_t asc;
121952889Sbostic 	register int status, ss, ir;
122052889Sbostic {
122152889Sbostic 	register asc_regmap_t *regs = asc->regs;
122252889Sbostic 	register State *state = &asc->st[asc->target];
122353080Sralph 	register int len;
122452889Sbostic 
122552889Sbostic 	/* check for previous chunk in buffer */
122653080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
122752889Sbostic 		/*
122852889Sbostic 		 * Only count bytes that have been copied to memory.
122952889Sbostic 		 * There may be some bytes in the FIFO if synchonous transfers
123052889Sbostic 		 * are in progress.
123152889Sbostic 		 */
123256819Sralph 		(*asc->dma_end)(asc, state, ASCDMA_READ);
123352889Sbostic 		ASC_TC_GET(regs, len);
123452889Sbostic 		len = state->dmalen - len;
123552889Sbostic 		bcopy(state->dmaBufAddr, state->buf, len);
123652889Sbostic 		state->buf += len;
123752889Sbostic 		state->buflen -= len;
123853080Sralph 	}
123952889Sbostic 
124052942Sralph 	/* setup to start reading the next chunk */
124152889Sbostic 	len = state->buflen;
1242*67476Smckusick #ifdef DEBUG
1243*67476Smckusick 	if (asc_logp == asc_log)
1244*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1245*67476Smckusick 	else
1246*67476Smckusick 		asc_logp[-1].resid = len;
1247*67476Smckusick #endif
124852889Sbostic 	if (len > state->dmaBufSize)
124952889Sbostic 		len = state->dmaBufSize;
125052889Sbostic 	state->dmalen = len;
125156819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
125252889Sbostic 	ASC_TC_PUT(regs, len);
125352942Sralph #ifdef DEBUG
125452942Sralph 	if (asc_debug > 2)
125552942Sralph 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
125652942Sralph #endif
125752942Sralph 
125852942Sralph 	/* check for next chunk */
125953080Sralph 	state->flags |= DMA_IN_PROGRESS;
126052889Sbostic 	if (len != state->buflen) {
126152889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
126256819Sralph 		readback(regs->asc_cmd);
126352942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
126452889Sbostic 		return (0);
126552889Sbostic 	}
126652889Sbostic 	return (1);
126752889Sbostic }
126852889Sbostic 
126952889Sbostic /* ARGSUSED */
127052889Sbostic static int
127152889Sbostic asc_last_dma_in(asc, status, ss, ir)
127252889Sbostic 	register asc_softc_t asc;
127352889Sbostic 	register int status, ss, ir;
127452889Sbostic {
127552889Sbostic 	register asc_regmap_t *regs = asc->regs;
127652889Sbostic 	register State *state = &asc->st[asc->target];
127752889Sbostic 	register int len, fifo;
127852889Sbostic 
127952889Sbostic 	/* copy data from buffer to main memory */
128056819Sralph 	(*asc->dma_end)(asc, state, ASCDMA_READ);
128152889Sbostic 	ASC_TC_GET(regs, len);
128252889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
128352889Sbostic #ifdef DEBUG
128452942Sralph 	if (asc_debug > 2)
128552889Sbostic 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
128652889Sbostic 			state->buflen, state->dmalen, len, fifo);
128752889Sbostic #endif
128852889Sbostic 	if (fifo) {
128952942Sralph 		/* device must be trying to send more than we expect */
129052889Sbostic 		regs->asc_cmd = ASC_CMD_FLUSH;
129156819Sralph 		readback(regs->asc_cmd);
129252889Sbostic 	}
129353080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
129452889Sbostic 	len = state->dmalen - len;
129552889Sbostic 	state->buflen -= len;
129652889Sbostic 	bcopy(state->dmaBufAddr, state->buf, len);
129752889Sbostic 
129852889Sbostic 	return (1);
129952889Sbostic }
130052889Sbostic 
130152889Sbostic /* ARGSUSED */
130252889Sbostic static int
130352942Sralph asc_resume_in(asc, status, ss, ir)
130452942Sralph 	register asc_softc_t asc;
130552942Sralph 	register int status, ss, ir;
130652942Sralph {
130752942Sralph 	register asc_regmap_t *regs = asc->regs;
130852942Sralph 	register State *state = &asc->st[asc->target];
130952942Sralph 	register int len;
131052942Sralph 
131152942Sralph 	/* setup to start reading the next chunk */
131252942Sralph 	len = state->buflen;
1313*67476Smckusick #ifdef DEBUG
1314*67476Smckusick 	if (asc_logp == asc_log)
1315*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1316*67476Smckusick 	else
1317*67476Smckusick 		asc_logp[-1].resid = len;
1318*67476Smckusick #endif
131952942Sralph 	if (len > state->dmaBufSize)
132052942Sralph 		len = state->dmaBufSize;
132152942Sralph 	state->dmalen = len;
132256819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
132352942Sralph 	ASC_TC_PUT(regs, len);
132452942Sralph #ifdef DEBUG
132552942Sralph 	if (asc_debug > 2)
132652942Sralph 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
132752942Sralph 			len);
132852942Sralph #endif
132952942Sralph 
133052942Sralph 	/* check for next chunk */
133153080Sralph 	state->flags |= DMA_IN_PROGRESS;
133252942Sralph 	if (len != state->buflen) {
133352942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
133456819Sralph 		readback(regs->asc_cmd);
133552942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
133652942Sralph 		return (0);
133752942Sralph 	}
133852942Sralph 	return (1);
133952942Sralph }
134052942Sralph 
134152942Sralph /* ARGSUSED */
134252942Sralph static int
134352889Sbostic asc_resume_dma_in(asc, status, ss, ir)
134452889Sbostic 	register asc_softc_t asc;
134552889Sbostic 	register int status, ss, ir;
134652889Sbostic {
134752889Sbostic 	register asc_regmap_t *regs = asc->regs;
134852889Sbostic 	register State *state = &asc->st[asc->target];
134952889Sbostic 	register int len, off;
135052889Sbostic 
135152889Sbostic 	/* setup to finish reading the current chunk */
135252889Sbostic 	len = state->dmaresid;
135352889Sbostic 	off = state->dmalen - len;
135452889Sbostic 	if ((off & 1) && state->sync_offset) {
135552889Sbostic 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
135652889Sbostic 			state->dmalen, len, off); /* XXX */
135752889Sbostic 		regs->asc_res_fifo = state->dmaBufAddr[off];
135852889Sbostic 	}
1359*67476Smckusick #ifdef DEBUG
1360*67476Smckusick 	if (asc_logp == asc_log)
1361*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1362*67476Smckusick 	else
1363*67476Smckusick 		asc_logp[-1].resid = len;
1364*67476Smckusick #endif
136556819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
136652889Sbostic 	ASC_TC_PUT(regs, len);
136752942Sralph #ifdef DEBUG
136852942Sralph 	if (asc_debug > 2)
136952942Sralph 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
137052942Sralph 			state->dmalen, state->buflen, len, off);
137152942Sralph #endif
137252942Sralph 
137352942Sralph 	/* check for next chunk */
137453080Sralph 	state->flags |= DMA_IN_PROGRESS;
137552889Sbostic 	if (state->dmalen != state->buflen) {
137652889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
137756819Sralph 		readback(regs->asc_cmd);
137852942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
137952889Sbostic 		return (0);
138052889Sbostic 	}
138152889Sbostic 	return (1);
138252889Sbostic }
138352889Sbostic 
138452889Sbostic /* ARGSUSED */
138552889Sbostic static int
138652889Sbostic asc_dma_out(asc, status, ss, ir)
138752889Sbostic 	register asc_softc_t asc;
138852889Sbostic 	register int status, ss, ir;
138952889Sbostic {
139052889Sbostic 	register asc_regmap_t *regs = asc->regs;
139152889Sbostic 	register State *state = &asc->st[asc->target];
139252889Sbostic 	register int len, fifo;
139352889Sbostic 
139453080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
139552889Sbostic 		/* check to be sure previous chunk was finished */
139652889Sbostic 		ASC_TC_GET(regs, len);
139752889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
139852889Sbostic 		if (len || fifo)
139952889Sbostic 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
140052889Sbostic 				state->buflen, state->dmalen, len, fifo); /* XXX */
140152889Sbostic 		len += fifo;
140252889Sbostic 		len = state->dmalen - len;
140353080Sralph 		state->buf += len;
140452889Sbostic 		state->buflen -= len;
140553080Sralph 	}
140652889Sbostic 
140758792Sralph 	/* setup for this chunk */
140853080Sralph 	len = state->buflen;
1409*67476Smckusick #ifdef DEBUG
1410*67476Smckusick 	if (asc_logp == asc_log)
1411*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1412*67476Smckusick 	else
1413*67476Smckusick 		asc_logp[-1].resid = len;
1414*67476Smckusick #endif
141553080Sralph 	if (len > state->dmaBufSize)
141653080Sralph 		len = state->dmaBufSize;
141753080Sralph 	state->dmalen = len;
141853080Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
141956819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
142052942Sralph 	ASC_TC_PUT(regs, len);
142152889Sbostic #ifdef DEBUG
142252889Sbostic 	if (asc_debug > 2)
142352942Sralph 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
142452889Sbostic #endif
142552889Sbostic 
142652889Sbostic 	/* check for next chunk */
142753080Sralph 	state->flags |= DMA_IN_PROGRESS;
142852889Sbostic 	if (len != state->buflen) {
142952889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
143056819Sralph 		readback(regs->asc_cmd);
143152942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
143252889Sbostic 		return (0);
143352889Sbostic 	}
143452889Sbostic 	return (1);
143552889Sbostic }
143652889Sbostic 
143752889Sbostic /* ARGSUSED */
143852889Sbostic static int
143952889Sbostic asc_last_dma_out(asc, status, ss, ir)
144052889Sbostic 	register asc_softc_t asc;
144152889Sbostic 	register int status, ss, ir;
144252889Sbostic {
144352889Sbostic 	register asc_regmap_t *regs = asc->regs;
144452889Sbostic 	register State *state = &asc->st[asc->target];
144552889Sbostic 	register int len, fifo;
144652889Sbostic 
144752889Sbostic 	ASC_TC_GET(regs, len);
144852889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
144952889Sbostic #ifdef DEBUG
145052889Sbostic 	if (asc_debug > 2)
145152889Sbostic 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
145253080Sralph 			state->buflen, state->dmalen, len, fifo);
145352942Sralph #endif
145452942Sralph 	if (fifo) {
145552942Sralph 		len += fifo;
145652942Sralph 		regs->asc_cmd = ASC_CMD_FLUSH;
145756819Sralph 		readback(regs->asc_cmd);
145858792Sralph 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
145958792Sralph 			state->buflen, state->dmalen, len, fifo);
146052942Sralph 	}
146153080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
146252889Sbostic 	len = state->dmalen - len;
146352889Sbostic 	state->buflen -= len;
146452889Sbostic 	return (1);
146552889Sbostic }
146652889Sbostic 
146752889Sbostic /* ARGSUSED */
146852889Sbostic static int
146952942Sralph asc_resume_out(asc, status, ss, ir)
147052942Sralph 	register asc_softc_t asc;
147152942Sralph 	register int status, ss, ir;
147252942Sralph {
147352942Sralph 	register asc_regmap_t *regs = asc->regs;
147452942Sralph 	register State *state = &asc->st[asc->target];
147552942Sralph 	register int len;
147652942Sralph 
147758792Sralph 	/* setup for this chunk */
147852942Sralph 	len = state->buflen;
1479*67476Smckusick #ifdef DEBUG
1480*67476Smckusick 	if (asc_logp == asc_log)
1481*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1482*67476Smckusick 	else
1483*67476Smckusick 		asc_logp[-1].resid = len;
1484*67476Smckusick #endif
148552942Sralph 	if (len > state->dmaBufSize)
148652942Sralph 		len = state->dmaBufSize;
148752942Sralph 	state->dmalen = len;
148852942Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
148956819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
149052942Sralph 	ASC_TC_PUT(regs, len);
149152942Sralph #ifdef DEBUG
149252942Sralph 	if (asc_debug > 2)
149352942Sralph 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
149452942Sralph 			len);
149552942Sralph #endif
149652942Sralph 
149752942Sralph 	/* check for next chunk */
149853080Sralph 	state->flags |= DMA_IN_PROGRESS;
149952942Sralph 	if (len != state->buflen) {
150052942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
150156819Sralph 		readback(regs->asc_cmd);
150252942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
150352942Sralph 		return (0);
150452942Sralph 	}
150552942Sralph 	return (1);
150652942Sralph }
150752942Sralph 
150852942Sralph /* ARGSUSED */
150952942Sralph static int
151052889Sbostic asc_resume_dma_out(asc, status, ss, ir)
151152889Sbostic 	register asc_softc_t asc;
151252889Sbostic 	register int status, ss, ir;
151352889Sbostic {
151452889Sbostic 	register asc_regmap_t *regs = asc->regs;
151552889Sbostic 	register State *state = &asc->st[asc->target];
151652889Sbostic 	register int len, off;
151752889Sbostic 
151852889Sbostic 	/* setup to finish writing this chunk */
151952889Sbostic 	len = state->dmaresid;
152052889Sbostic 	off = state->dmalen - len;
152152889Sbostic 	if (off & 1) {
152252889Sbostic 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
152352889Sbostic 			state->dmalen, len, off); /* XXX */
152452889Sbostic 		regs->asc_fifo = state->dmaBufAddr[off];
152552889Sbostic 		off++;
152652889Sbostic 		len--;
152752889Sbostic 	}
1528*67476Smckusick #ifdef DEBUG
1529*67476Smckusick 	if (asc_logp == asc_log)
1530*67476Smckusick 		asc_log[NLOG - 1].resid = len;
1531*67476Smckusick 	else
1532*67476Smckusick 		asc_logp[-1].resid = len;
1533*67476Smckusick #endif
153456819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
153552889Sbostic 	ASC_TC_PUT(regs, len);
153652942Sralph #ifdef DEBUG
153752942Sralph 	if (asc_debug > 2)
153852942Sralph 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
153952942Sralph 			state->dmalen, state->buflen, len, off);
154052942Sralph #endif
154152942Sralph 
154252942Sralph 	/* check for next chunk */
154353080Sralph 	state->flags |= DMA_IN_PROGRESS;
154452889Sbostic 	if (state->dmalen != state->buflen) {
154552889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
154656819Sralph 		readback(regs->asc_cmd);
154752942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
154852889Sbostic 		return (0);
154952889Sbostic 	}
155052889Sbostic 	return (1);
155152889Sbostic }
155252889Sbostic 
155352889Sbostic /* ARGSUSED */
155452889Sbostic static int
155552889Sbostic asc_sendsync(asc, status, ss, ir)
155652889Sbostic 	register asc_softc_t asc;
155752889Sbostic 	register int status, ss, ir;
155852889Sbostic {
155952889Sbostic 	register asc_regmap_t *regs = asc->regs;
156053080Sralph 	register State *state = &asc->st[asc->target];
156152889Sbostic 
156253080Sralph 	/* send the extended synchronous negotiation message */
156352889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
156452889Sbostic 	MachEmptyWriteBuffer();
156552889Sbostic 	regs->asc_fifo = 3;
156652889Sbostic 	MachEmptyWriteBuffer();
156752889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
156852889Sbostic 	MachEmptyWriteBuffer();
156952889Sbostic 	regs->asc_fifo = SCSI_MIN_PERIOD;
157052889Sbostic 	MachEmptyWriteBuffer();
157152889Sbostic 	regs->asc_fifo = ASC_MAX_OFFSET;
157253080Sralph 	/* state to resume after we see the sync reply message */
157353080Sralph 	state->script = asc->script + 2;
157453080Sralph 	state->msglen = 0;
157552889Sbostic 	return (1);
157652889Sbostic }
157752889Sbostic 
157852889Sbostic /* ARGSUSED */
157952889Sbostic static int
158052889Sbostic asc_replysync(asc, status, ss, ir)
158152889Sbostic 	register asc_softc_t asc;
158252889Sbostic 	register int status, ss, ir;
158352889Sbostic {
158452889Sbostic 	register asc_regmap_t *regs = asc->regs;
158552889Sbostic 	register State *state = &asc->st[asc->target];
158652889Sbostic 
158752889Sbostic #ifdef DEBUG
158852889Sbostic 	if (asc_debug > 2)
158952889Sbostic 		printf("asc_replysync: %x %x\n",
159056819Sralph 			asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
159152889Sbostic 			state->sync_offset);
159252889Sbostic #endif
159352889Sbostic 	/* send synchronous transfer in response to a request */
159452889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
159552889Sbostic 	MachEmptyWriteBuffer();
159652889Sbostic 	regs->asc_fifo = 3;
159752889Sbostic 	MachEmptyWriteBuffer();
159852889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
159952889Sbostic 	MachEmptyWriteBuffer();
160056819Sralph 	regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
160152889Sbostic 	MachEmptyWriteBuffer();
160252889Sbostic 	regs->asc_fifo = state->sync_offset;
160352889Sbostic 	regs->asc_cmd = ASC_CMD_XFER_INFO;
160456819Sralph 	readback(regs->asc_cmd);
160552889Sbostic 
160652889Sbostic 	/* return to the appropriate script */
160752889Sbostic 	if (!state->script) {
160852889Sbostic #ifdef DEBUG
160952889Sbostic 		asc_DumpLog("asc_replsync");
161052889Sbostic #endif
161152889Sbostic 		panic("asc_replysync");
161252889Sbostic 	}
161352889Sbostic 	asc->script = state->script;
161452889Sbostic 	state->script = (script_t *)0;
161552889Sbostic 	return (0);
161652889Sbostic }
161752889Sbostic 
161852889Sbostic /* ARGSUSED */
161952889Sbostic static int
162052942Sralph asc_msg_in(asc, status, ss, ir)
162152889Sbostic 	register asc_softc_t asc;
162252889Sbostic 	register int status, ss, ir;
162352889Sbostic {
162452889Sbostic 	register asc_regmap_t *regs = asc->regs;
162552889Sbostic 	register State *state = &asc->st[asc->target];
162652889Sbostic 	register int msg;
162752889Sbostic 	int i;
162852889Sbostic 
162952889Sbostic 	/* read one message byte */
163052889Sbostic 	msg = regs->asc_fifo;
163152889Sbostic #ifdef DEBUG
163252889Sbostic 	if (asc_logp == asc_log)
163352889Sbostic 		asc_log[NLOG - 1].msg = msg;
163452889Sbostic 	else
163552889Sbostic 		asc_logp[-1].msg = msg;
163652889Sbostic #endif
163752889Sbostic 
163852889Sbostic 	/* check for multi-byte message */
163952889Sbostic 	if (state->msglen != 0) {
164052889Sbostic 		/* first byte is the message length */
164152889Sbostic 		if (state->msglen < 0) {
164252889Sbostic 			state->msglen = msg;
164352889Sbostic 			return (1);
164452889Sbostic 		}
164552889Sbostic 		if (state->msgcnt >= state->msglen)
164652889Sbostic 			goto abort;
164752889Sbostic 		state->msg_in[state->msgcnt++] = msg;
164852889Sbostic 
164952889Sbostic 		/* did we just read the last byte of the message? */
165052889Sbostic 		if (state->msgcnt != state->msglen)
165152889Sbostic 			return (1);
165252889Sbostic 
165352889Sbostic 		/* process an extended message */
165452889Sbostic #ifdef DEBUG
165552889Sbostic 		if (asc_debug > 2)
165652942Sralph 			printf("asc_msg_in: msg %x %x %x\n",
165752889Sbostic 				state->msg_in[0],
165852889Sbostic 				state->msg_in[1],
165952889Sbostic 				state->msg_in[2]);
166052889Sbostic #endif
166152889Sbostic 		switch (state->msg_in[0]) {
166252889Sbostic 		case SCSI_SYNCHRONOUS_XFER:
166352889Sbostic 			state->flags |= DID_SYNC;
166452889Sbostic 			state->sync_offset = state->msg_in[2];
166552889Sbostic 
166652889Sbostic 			/* convert SCSI period to ASC period */
166756819Sralph 			i = state->msg_in[1] / asc->tb_ticks;
166856819Sralph 			if (i < asc->min_period)
166956819Sralph 				i = asc->min_period;
167056819Sralph 			else if (i >= asc->max_period) {
167152889Sbostic 				/* can't do sync transfer, period too long */
167252889Sbostic 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
167352889Sbostic 					asc - asc_softc, asc->target, i);
167456819Sralph 				i = asc->max_period;
167552889Sbostic 				state->sync_offset = 0;
167652889Sbostic 			}
167756819Sralph 			if ((i * asc->tb_ticks) != state->msg_in[1])
167852889Sbostic 				i++;
167952889Sbostic 			state->sync_period = i & 0x1F;
168052889Sbostic 
168152889Sbostic 			/*
168252889Sbostic 			 * If this is a request, check minimums and
168352889Sbostic 			 * send back an acknowledge.
168452889Sbostic 			 */
168552889Sbostic 			if (!(state->flags & TRY_SYNC)) {
168652889Sbostic 				regs->asc_cmd = ASC_CMD_SET_ATN;
168756819Sralph 				readback(regs->asc_cmd);
168852889Sbostic 
168956819Sralph 				if (state->sync_period < asc->min_period)
169052889Sbostic 					state->sync_period =
169156819Sralph 						asc->min_period;
169252889Sbostic 				if (state->sync_offset > ASC_MAX_OFFSET)
169352889Sbostic 					state->sync_offset =
169452889Sbostic 						ASC_MAX_OFFSET;
169552889Sbostic 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
169652889Sbostic 				regs->asc_syn_p = state->sync_period;
169756819Sralph 				readback(regs->asc_syn_p);
169852889Sbostic 				regs->asc_syn_o = state->sync_offset;
169956819Sralph 				readback(regs->asc_syn_o);
170052889Sbostic 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
170156819Sralph 				readback(regs->asc_cmd);
170252889Sbostic 				return (0);
170352889Sbostic 			}
170452889Sbostic 
170552889Sbostic 			regs->asc_syn_p = state->sync_period;
170656819Sralph 			readback(regs->asc_syn_p);
170752889Sbostic 			regs->asc_syn_o = state->sync_offset;
170856819Sralph 			readback(regs->asc_syn_o);
170952889Sbostic 			goto done;
171052889Sbostic 
171152889Sbostic 		default:
171252889Sbostic 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
171352889Sbostic 				asc - asc_softc, asc->target,
171452889Sbostic 				state->msg_in[0]);
171552889Sbostic 			goto reject;
171652889Sbostic 		}
171752889Sbostic 	}
171852889Sbostic 
171952889Sbostic 	/* process first byte of a message */
172052889Sbostic #ifdef DEBUG
172152889Sbostic 	if (asc_debug > 2)
172252942Sralph 		printf("asc_msg_in: msg %x\n", msg);
172352889Sbostic #endif
172452889Sbostic 	switch (msg) {
172552889Sbostic #if 0
172652889Sbostic 	case SCSI_MESSAGE_REJECT:
172752889Sbostic 		printf(" did not like SYNCH xfer "); /* XXX */
172852889Sbostic 		state->flags |= DID_SYNC;
172952889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
173056819Sralph 		readback(regs->asc_cmd);
173152889Sbostic 		status = asc_wait(regs, ASC_CSR_INT);
173252889Sbostic 		ir = regs->asc_intr;
173352889Sbostic 		/* some just break out here, some dont */
173452889Sbostic 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
173552889Sbostic 			regs->asc_fifo = SCSI_ABORT;
173652889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
173756819Sralph 			readback(regs->asc_cmd);
173852889Sbostic 			status = asc_wait(regs, ASC_CSR_INT);
173952889Sbostic 			ir = regs->asc_intr;
174052889Sbostic 		}
174152889Sbostic 		if (ir & ASC_INT_DISC) {
174252889Sbostic 			asc_end(asc, status, 0, ir);
174352889Sbostic 			return (0);
174452889Sbostic 		}
174552889Sbostic 		goto status;
174652889Sbostic #endif
174752889Sbostic 
174852889Sbostic 	case SCSI_EXTENDED_MSG: /* read an extended message */
174952889Sbostic 		/* setup to read message length next */
175052889Sbostic 		state->msglen = -1;
175152889Sbostic 		state->msgcnt = 0;
175252889Sbostic 		return (1);
175352889Sbostic 
175452889Sbostic 	case SCSI_NO_OP:
175552889Sbostic 		break;
175652889Sbostic 
175752889Sbostic 	case SCSI_SAVE_DATA_POINTER:
175852889Sbostic 		/* expect another message */
175952889Sbostic 		return (1);
176052889Sbostic 
176152889Sbostic 	case SCSI_RESTORE_POINTERS:
176252889Sbostic 		/*
176352889Sbostic 		 * Need to do the following if resuming synchonous data in
176452889Sbostic 		 * on an odd byte boundary.
176552889Sbostic 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
176652889Sbostic 		 */
176752889Sbostic 		break;
176852889Sbostic 
176952889Sbostic 	case SCSI_DISCONNECT:
177052889Sbostic 		if (state->flags & DISCONN)
177152889Sbostic 			goto abort;
177252889Sbostic 		state->flags |= DISCONN;
177352942Sralph 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
177456819Sralph 		readback(regs->asc_cmd);
177552942Sralph 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
177652942Sralph 		return (0);
177752889Sbostic 
177852889Sbostic 	default:
177952889Sbostic 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
178052889Sbostic 			asc - asc_softc, asc->target, msg);
178152889Sbostic 	reject:
178252889Sbostic 		/* request a message out before acknowledging this message */
178352889Sbostic 		state->msg_out = SCSI_MESSAGE_REJECT;
178452889Sbostic 		regs->asc_cmd = ASC_CMD_SET_ATN;
178556819Sralph 		readback(regs->asc_cmd);
178652889Sbostic 	}
178752889Sbostic 
178852889Sbostic done:
178952889Sbostic 	/* return to original script */
179052889Sbostic 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
179156819Sralph 	readback(regs->asc_cmd);
179252889Sbostic 	if (!state->script) {
179352889Sbostic 	abort:
179452889Sbostic #ifdef DEBUG
179552942Sralph 		asc_DumpLog("asc_msg_in");
179652889Sbostic #endif
179752942Sralph 		panic("asc_msg_in");
179852889Sbostic 	}
179952889Sbostic 	asc->script = state->script;
180052889Sbostic 	state->script = (script_t *)0;
180152889Sbostic 	return (0);
180252889Sbostic }
180352889Sbostic 
180452942Sralph /* ARGSUSED */
180552942Sralph static int
180652942Sralph asc_disconnect(asc, status, ss, ir)
180752942Sralph 	register asc_softc_t asc;
180852942Sralph 	register int status, ss, ir;
180952942Sralph {
181052942Sralph 	register State *state = &asc->st[asc->target];
181152942Sralph 
181258658Sralph #ifdef DIAGNOSTIC
181358658Sralph 	if (!(state->flags & DISCONN)) {
181458658Sralph 		printf("asc_disconnect: device %d: DISCONN not set!\n",
181558658Sralph 			asc->target);
181658658Sralph 	}
181758658Sralph #endif
181852942Sralph 	asc->target = -1;
181952942Sralph 	asc->state = ASC_STATE_RESEL;
182052942Sralph 	return (1);
182152942Sralph }
182252942Sralph 
182356819Sralph /*
182458792Sralph  * DMA handling routines. For a turbochannel device, just set the dmar.
182558792Sralph  * For the I/O ASIC, handle the actual DMA interface.
182656819Sralph  */
182756819Sralph static void
182856819Sralph tb_dma_start(asc, state, cp, flag)
182956819Sralph 	asc_softc_t asc;
183056819Sralph 	State *state;
183156819Sralph 	caddr_t cp;
183256819Sralph 	int flag;
183356819Sralph {
183456819Sralph 
183556819Sralph 	if (flag == ASCDMA_WRITE)
183656819Sralph 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
183756819Sralph 	else
183856819Sralph 		*asc->dmar = ASC_DMA_ADDR(cp);
183956819Sralph }
184056819Sralph 
184156819Sralph static void
184256819Sralph tb_dma_end(asc, state, flag)
184356819Sralph 	asc_softc_t asc;
184456819Sralph 	State *state;
184556819Sralph 	int flag;
184656819Sralph {
184756819Sralph 
184856819Sralph }
184956819Sralph 
185056819Sralph static void
185156819Sralph asic_dma_start(asc, state, cp, flag)
185256819Sralph 	asc_softc_t asc;
185356819Sralph 	State *state;
185456819Sralph 	caddr_t cp;
185556819Sralph 	int flag;
185656819Sralph {
185756819Sralph 	register volatile u_int *ssr = (volatile u_int *)
185857233Sralph 		ASIC_REG_CSR(asic_base);
185956819Sralph 	u_int phys, nphys;
186056819Sralph 
186156819Sralph 	/* stop DMA engine first */
186256819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
186358658Sralph 	*((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
186456819Sralph 
186556819Sralph 	phys = MACH_CACHED_TO_PHYS(cp);
186656819Sralph 	cp = (caddr_t)pmax_trunc_page(cp + NBPG);
186756819Sralph 	nphys = MACH_CACHED_TO_PHYS(cp);
186856819Sralph 
186956819Sralph 	asc->dma_next = cp;
187056819Sralph 	asc->dma_xfer = state->dmalen - (nphys - phys);
187156819Sralph 
187257233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) =
187356819Sralph 		ASIC_DMA_ADDR(phys);
187457233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
187556819Sralph 		ASIC_DMA_ADDR(nphys);
187656819Sralph 	if (flag == ASCDMA_READ)
187756819Sralph 		*ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI;
187856819Sralph 	else
187956819Sralph 		*ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI;
188056819Sralph 	MachEmptyWriteBuffer();
188156819Sralph }
188256819Sralph 
188356819Sralph static void
188456819Sralph asic_dma_end(asc, state, flag)
188556819Sralph 	asc_softc_t asc;
188656819Sralph 	State *state;
188756819Sralph 	int flag;
188856819Sralph {
188956819Sralph 	register volatile u_int *ssr = (volatile u_int *)
189057233Sralph 		ASIC_REG_CSR(asic_base);
189160301Sralph 	register volatile u_int *dmap = (volatile u_int *)
189260301Sralph 		ASIC_REG_SCSI_DMAPTR(asic_base);
189360301Sralph 	register u_short *to;
189460301Sralph 	register int w;
189556819Sralph 	int nb;
189656819Sralph 
189756819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
189860301Sralph 	to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3);
189960301Sralph 	*dmap = -1;
190057233Sralph 	*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
190156819Sralph 	MachEmptyWriteBuffer();
190256819Sralph 
190356819Sralph 	if (flag == ASCDMA_READ) {
190456819Sralph 		MachFlushDCache(MACH_PHYS_TO_CACHED(
190556819Sralph 		    MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
190657233Sralph 		if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) {
190756819Sralph 			/* pick up last upto6 bytes, sigh. */
190856819Sralph 
190956819Sralph 			/* Last byte really xferred is.. */
191057233Sralph 			w = *(int *)ASIC_REG_SCSI_SDR0(asic_base);
191156819Sralph 			*to++ = w;
191256819Sralph 			if (--nb > 0) {
191356819Sralph 				w >>= 16;
191456819Sralph 				*to++ = w;
191556819Sralph 			}
191656819Sralph 			if (--nb > 0) {
191757233Sralph 				w = *(int *)ASIC_REG_SCSI_SDR1(asic_base);
191856819Sralph 				*to++ = w;
191956819Sralph 			}
192056819Sralph 		}
192156819Sralph 	}
192256819Sralph }
192356819Sralph 
192457233Sralph #ifdef notdef
192556819Sralph /*
192656819Sralph  * Called by asic_intr() for scsi dma pointer update interrupts.
192756819Sralph  */
192856819Sralph void
192956819Sralph asc_dma_intr()
193056819Sralph {
193156819Sralph 	asc_softc_t asc = &asc_softc[0];
193256819Sralph 	u_int next_phys;
193356819Sralph 
193456819Sralph 	asc->dma_xfer -= NBPG;
193556819Sralph 	if (asc->dma_xfer <= -NBPG) {
193656819Sralph 		volatile u_int *ssr = (volatile u_int *)
193757233Sralph 			ASIC_REG_CSR(asic_base);
193856819Sralph 		*ssr &= ~ASIC_CSR_DMAEN_SCSI;
193956819Sralph 	} else {
194056819Sralph 		asc->dma_next += NBPG;
194156819Sralph 		next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
194256819Sralph 	}
194357233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
194456819Sralph 		ASIC_DMA_ADDR(next_phys);
194556819Sralph 	MachEmptyWriteBuffer();
194656819Sralph }
194757233Sralph #endif
194856819Sralph 
194952889Sbostic #ifdef DEBUG
195052889Sbostic asc_DumpLog(str)
195152889Sbostic 	char *str;
195252889Sbostic {
195352889Sbostic 	register struct asc_log *lp;
195452889Sbostic 	register u_int status;
195552889Sbostic 
195652889Sbostic 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
195752889Sbostic 		asc_debug_bn, asc_debug_sz);
195858570Sralph 	lp = asc_logp;
195958570Sralph 	do {
196052889Sbostic 		status = lp->status;
196158658Sralph 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n",
196252889Sbostic 			status >> 24,
196352889Sbostic 			lp->target,
196452889Sbostic 			(status >> 16) & 0xFF,
196552889Sbostic 			(status >> 8) & 0xFF,
196652889Sbostic 			status & 0XFF,
196752889Sbostic 			lp->state,
196852889Sbostic 			asc_scripts[lp->state].condition,
196958658Sralph 			lp->msg, lp->resid);
197052889Sbostic 		if (++lp >= &asc_log[NLOG])
197152889Sbostic 			lp = asc_log;
197258570Sralph 	} while (lp != asc_logp);
197352889Sbostic }
197452889Sbostic #endif
197552889Sbostic 
197652889Sbostic #endif	/* NASC > 0 */
1977