xref: /csrg-svn/sys/pmax/dev/asc.c (revision 68011)
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*68011Smckusick  *	@(#)asc.c	8.5 (Berkeley) 11/30/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
225*68011Smckusick #define	SCRIPT_DONE		8
22652942Sralph #define	SCRIPT_MSG_IN		9
22752942Sralph #define	SCRIPT_REPLY_SYNC	11
22852889Sbostic #define	SCRIPT_TRY_SYNC		12
22952942Sralph #define	SCRIPT_DISCONNECT	15
23052942Sralph #define	SCRIPT_RESEL		16
23152942Sralph #define	SCRIPT_RESUME_IN	17
23252942Sralph #define	SCRIPT_RESUME_DMA_IN	18
23352942Sralph #define	SCRIPT_RESUME_OUT	19
23452942Sralph #define	SCRIPT_RESUME_DMA_OUT	20
23552942Sralph #define	SCRIPT_RESUME_NO_DATA	21
23652889Sbostic 
23752889Sbostic /*
23852889Sbostic  * Scripts
23952889Sbostic  */
24052889Sbostic script_t asc_scripts[] = {
24152942Sralph 	/* start data in */
24252889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
24352889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
24452942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
24552889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
24652889Sbostic 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
24752942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
24852889Sbostic 
24958570Sralph 	/* continue data in after a chunk is finished */
25052942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/*  2 */
25152942Sralph 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
25252942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
25352942Sralph 
25452942Sralph 	/* start data out */
25552942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  3 */
25652889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
25752942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
25852942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  4 */
25952889Sbostic 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
26052942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
26152889Sbostic 
26258570Sralph 	/* continue data out after a chunk is finished */
26352942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/*  5 */
26452942Sralph 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
26552942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
26652942Sralph 
26752889Sbostic 	/* simple command with no data transfer */
26852942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  6 */
26952889Sbostic 		script_nop, ASC_CMD_I_COMPLETE,
27052942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
27152889Sbostic 
27252889Sbostic 	/* get status and finish command */
27352942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
27452889Sbostic 		asc_get_status, ASC_CMD_MSG_ACPT,
275*68011Smckusick 		&asc_scripts[SCRIPT_DONE]},
27652942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  8 */
27752889Sbostic 		asc_end, ASC_CMD_NOP,
278*68011Smckusick 		&asc_scripts[SCRIPT_DONE]},
27952889Sbostic 
28052889Sbostic 	/* message in */
28152942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  9 */
28252942Sralph 		asc_msg_in, ASC_CMD_MSG_ACPT,
28352942Sralph 		&asc_scripts[SCRIPT_MSG_IN + 1]},
28452942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 10 */
28552889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
28652942Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
28752889Sbostic 
28852889Sbostic 	/* send synchonous negotiation reply */
28952942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/* 11 */
29052889Sbostic 		asc_replysync, ASC_CMD_XFER_INFO,
29152942Sralph 		&asc_scripts[SCRIPT_REPLY_SYNC]},
29252889Sbostic 
29352889Sbostic 	/* try to negotiate synchonous transfer parameters */
29452889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
29552889Sbostic 		asc_sendsync, ASC_CMD_XFER_INFO,
29653080Sralph 		&asc_scripts[SCRIPT_TRY_SYNC + 1]},
29753080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 13 */
29852889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
29953080Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
30053080Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND),			/* 14 */
30153080Sralph 		script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
30253080Sralph 		&asc_scripts[SCRIPT_RESUME_NO_DATA]},
30352889Sbostic 
30452942Sralph 	/* handle a disconnect */
30552942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO),			/* 15 */
30652942Sralph 		asc_disconnect, ASC_CMD_ENABLE_SEL,
30752942Sralph 		&asc_scripts[SCRIPT_RESEL]},
30852942Sralph 
30952889Sbostic 	/* reselect sequence: this is just a placeholder so match fails */
31052942Sralph 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 16 */
31152889Sbostic 		script_nop, ASC_CMD_MSG_ACPT,
31252942Sralph 		&asc_scripts[SCRIPT_RESEL]},
31352889Sbostic 
31452942Sralph 	/* resume data in after a message */
31552942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 17 */
31652942Sralph 		asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
31752942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
31852942Sralph 
31952942Sralph 	/* resume partial DMA data in after a message */
32052942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 18 */
32152889Sbostic 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
32252942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
32352889Sbostic 
32452942Sralph 	/* resume data out after a message */
32552942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 19 */
32652942Sralph 		asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
32752942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
32852942Sralph 
32952942Sralph 	/* resume partial DMA data out after a message */
33052942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 20 */
33152889Sbostic 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
33252942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
33352942Sralph 
33452942Sralph 	/* resume after a message when there is no more data */
33552942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/* 21 */
33652942Sralph 		script_nop, ASC_CMD_I_COMPLETE,
33752942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
33852889Sbostic };
33952889Sbostic 
34052889Sbostic /*
34152889Sbostic  * State kept for each active SCSI device.
34252889Sbostic  */
34352889Sbostic typedef struct scsi_state {
34452889Sbostic 	script_t *script;	/* saved script while processing error */
34552889Sbostic 	int	statusByte;	/* status byte returned during STATUS_PHASE */
34652889Sbostic 	int	error;		/* errno to pass back to device driver */
34752889Sbostic 	u_char	*dmaBufAddr;	/* DMA buffer address */
34852889Sbostic 	u_int	dmaBufSize;	/* DMA buffer size */
34952889Sbostic 	int	dmalen;		/* amount to transfer in this chunk */
35052889Sbostic 	int	dmaresid;	/* amount not transfered if chunk suspended */
35152889Sbostic 	int	buflen;		/* total remaining amount of data to transfer */
35252889Sbostic 	char	*buf;		/* current pointer within scsicmd->buf */
35352889Sbostic 	int	flags;		/* see below */
35452889Sbostic 	int	msglen;		/* number of message bytes to read */
35552889Sbostic 	int	msgcnt;		/* number of message bytes received */
35652889Sbostic 	u_char	sync_period;	/* DMA synchronous period */
35752889Sbostic 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
35852889Sbostic 	u_char	msg_out;	/* next MSG_OUT byte to send */
35952889Sbostic 	u_char	msg_in[16];	/* buffer for multibyte messages */
36052889Sbostic } State;
36152889Sbostic 
36252889Sbostic /* state flags */
36352889Sbostic #define DISCONN		0x01	/* true if currently disconnected from bus */
36453080Sralph #define DMA_IN_PROGRESS	0x02	/* true if data DMA started */
36552889Sbostic #define DMA_IN		0x04	/* true if reading from SCSI device */
36652889Sbostic #define DMA_OUT		0x10	/* true if writing to SCSI device */
36752889Sbostic #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
36852889Sbostic #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
36958658Sralph #define PARITY_ERR	0x80	/* true if parity error seen */
37052889Sbostic 
37152889Sbostic /*
37252889Sbostic  * State kept for each active SCSI host interface (53C94).
37352889Sbostic  */
37452889Sbostic struct asc_softc {
37552889Sbostic 	asc_regmap_t	*regs;		/* chip address */
37652889Sbostic 	volatile int	*dmar;		/* DMA address register address */
37756819Sralph 	u_char		*buff;		/* RAM buffer address (uncached) */
37852889Sbostic 	int		myid;		/* SCSI ID of this interface */
37952889Sbostic 	int		myidmask;	/* ~(1 << myid) */
38052889Sbostic 	int		state;		/* current SCSI connection state */
38152889Sbostic 	int		target;		/* target SCSI ID if busy */
38252889Sbostic 	script_t	*script;	/* next expected interrupt & action */
38352889Sbostic 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
38452889Sbostic 	State		st[ASC_NCMD];	/* state info for each active command */
38556819Sralph 	void		(*dma_start)();	/* Start dma routine */
38656819Sralph 	void		(*dma_end)();	/* End dma routine */
38756819Sralph 	u_char		*dma_next;
38856819Sralph 	int		dma_xfer;	/* Dma len still to go */
38956819Sralph 	int		min_period;	/* Min transfer period clk/byte */
39056819Sralph 	int		max_period;	/* Max transfer period clk/byte */
39156819Sralph 	int		ccf;		/* CCF, whatever that really is? */
39256819Sralph 	int		timeout_250;	/* 250ms timeout */
39356819Sralph 	int		tb_ticks;	/* 4ns. ticks/tb channel ticks */
39452889Sbostic } asc_softc[NASC];
39552889Sbostic 
39652889Sbostic #define	ASC_STATE_IDLE		0	/* idle state */
39752889Sbostic #define	ASC_STATE_BUSY		1	/* selecting or currently connected */
39852889Sbostic #define ASC_STATE_TARGET	2	/* currently selected as target */
39952889Sbostic #define ASC_STATE_RESEL		3	/* currently waiting for reselect */
40052889Sbostic 
40152889Sbostic typedef struct asc_softc *asc_softc_t;
40252889Sbostic 
40352889Sbostic /*
40456819Sralph  * Dma operations.
40556819Sralph  */
40656819Sralph #define	ASCDMA_READ	1
40756819Sralph #define	ASCDMA_WRITE	2
40856819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();
40957233Sralph extern u_long asc_iomem;
41057233Sralph extern u_long asic_base;
41156819Sralph 
41256819Sralph /*
41352889Sbostic  * Definition of the controller for the auto-configuration program.
41452889Sbostic  */
41552889Sbostic int	asc_probe();
41652889Sbostic void	asc_start();
41752889Sbostic void	asc_intr();
41852889Sbostic struct	driver ascdriver = {
41952889Sbostic 	"asc", asc_probe, asc_start, 0, asc_intr,
42052889Sbostic };
42152889Sbostic 
42252889Sbostic /*
42352889Sbostic  * Test to see if device is present.
42452889Sbostic  * Return true if found and initialized ok.
42552889Sbostic  */
asc_probe(cp)42652889Sbostic asc_probe(cp)
42752889Sbostic 	register struct pmax_ctlr *cp;
42852889Sbostic {
42952889Sbostic 	register asc_softc_t asc;
43052889Sbostic 	register asc_regmap_t *regs;
43152889Sbostic 	int unit, id, s, i;
43257233Sralph 	int bufsiz;
43352889Sbostic 
43452889Sbostic 	if ((unit = cp->pmax_unit) >= NASC)
43552889Sbostic 		return (0);
43652889Sbostic 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
43752889Sbostic 		return (0);
43852889Sbostic 	asc = &asc_softc[unit];
43952889Sbostic 
44052889Sbostic 	/*
44152889Sbostic 	 * Initialize hw descriptor, cache some pointers
44252889Sbostic 	 */
44352889Sbostic 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
44452889Sbostic 
44556819Sralph 	/*
44656819Sralph 	 * Set up machine dependencies.
44756819Sralph 	 * 1) how to do dma
44856819Sralph 	 * 2) timing based on turbochannel frequency
44956819Sralph 	 */
45056819Sralph 	switch (pmax_boardtype) {
45156819Sralph 	case DS_3MIN:
45256819Sralph 	case DS_MAXINE:
45357233Sralph 	case DS_3MAXPLUS:
45456819Sralph 	    if (unit == 0) {
45557233Sralph 		asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
45657233Sralph 		bufsiz = 8192;
45757233Sralph 		*((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1;
45857233Sralph 		*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
45957233Sralph 		*((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
46056819Sralph 		asc->dma_start = asic_dma_start;
46156819Sralph 		asc->dma_end = asic_dma_end;
46256819Sralph 		break;
46356819Sralph 	    }
46456819Sralph 	    /*
46556819Sralph 	     * Fall through for turbochannel option.
46656819Sralph 	     */
46756819Sralph 	case DS_3MAX:
46856819Sralph 	default:
46956819Sralph 	    asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
47056819Sralph 	    asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
47157233Sralph 	    bufsiz = PER_TGT_DMA_SIZE;
47256819Sralph 	    asc->dma_start = tb_dma_start;
47356819Sralph 	    asc->dma_end = tb_dma_end;
47456819Sralph 	};
47556819Sralph 	/*
47656819Sralph 	 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and
47756819Sralph 	 * maxine are 12.5Mhz.
47856819Sralph 	 */
47956819Sralph 	switch (pmax_boardtype) {
48056819Sralph 	case DS_3MAX:
48157233Sralph 	case DS_3MAXPLUS:
48256819Sralph 		asc->min_period = ASC_MIN_PERIOD25;
48356819Sralph 		asc->max_period = ASC_MAX_PERIOD25;
48456819Sralph 		asc->ccf = ASC_CCF(25);
48556819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);
48656819Sralph 		asc->tb_ticks = 10;
48756819Sralph 		break;
48856819Sralph 	case DS_3MIN:
48956819Sralph 	case DS_MAXINE:
49056819Sralph 	default:
49156819Sralph 		asc->min_period = ASC_MIN_PERIOD12;
49256819Sralph 		asc->max_period = ASC_MAX_PERIOD12;
49356819Sralph 		asc->ccf = ASC_CCF(13);
49456819Sralph 		asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);
49556819Sralph 		asc->tb_ticks = 20;
49656819Sralph 		break;
49756819Sralph 	};
49856819Sralph 
49952889Sbostic 	asc->state = ASC_STATE_IDLE;
50052889Sbostic 	asc->target = -1;
50152889Sbostic 
50252889Sbostic 	regs = asc->regs;
50352889Sbostic 
50452889Sbostic 	/*
50552889Sbostic 	 * Reset chip, fully.  Note that interrupts are already enabled.
50652889Sbostic 	 */
50752889Sbostic 	s = splbio();
50852889Sbostic 
50952889Sbostic 	/* preserve our ID for now */
51052889Sbostic 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
51152889Sbostic 	asc->myidmask = ~(1 << asc->myid);
51252889Sbostic 
51352889Sbostic 	asc_reset(asc, regs);
51452889Sbostic 
51552889Sbostic 	/*
51652889Sbostic 	 * Our SCSI id on the bus.
51752889Sbostic 	 * The user can set this via the prom on 3maxen/pmaxen.
51852889Sbostic 	 * If this changes it is easy to fix: make a default that
51952889Sbostic 	 * can be changed as boot arg.
52052889Sbostic 	 */
52152889Sbostic #ifdef	unneeded
52252889Sbostic 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
52352889Sbostic 			      (scsi_initiator_id[unit] & 0x7);
52452889Sbostic #endif
52552889Sbostic 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
52652889Sbostic 	splx(s);
52752889Sbostic 
52852889Sbostic 	/*
52952889Sbostic 	 * Statically partition the DMA buffer between targets.
53052889Sbostic 	 * This way we will eventually be able to attach/detach
53152889Sbostic 	 * drives on-fly.  And 18k/target is plenty for normal use.
53252889Sbostic 	 */
53352889Sbostic 
53452889Sbostic 	/*
53552889Sbostic 	 * Give each target its own DMA buffer region.
53652889Sbostic 	 * We may want to try ping ponging buffers later.
53752889Sbostic 	 */
53852889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
53957233Sralph 		asc->st[i].dmaBufAddr = asc->buff + bufsiz * i;
54057233Sralph 		asc->st[i].dmaBufSize = bufsiz;
54152889Sbostic 	}
54252889Sbostic 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
54352889Sbostic 		unit, cp->pmax_addr, cp->pmax_pri, id);
54452889Sbostic 	return (1);
54552889Sbostic }
54652889Sbostic 
54752889Sbostic /*
54852889Sbostic  * Start activity on a SCSI device.
54952889Sbostic  * We maintain information on each device separately since devices can
55052889Sbostic  * connect/disconnect during an operation.
55152889Sbostic  */
55252889Sbostic void
asc_start(scsicmd)55352889Sbostic asc_start(scsicmd)
55452889Sbostic 	register ScsiCmd *scsicmd;	/* command to start */
55552889Sbostic {
55652889Sbostic 	register struct scsi_device *sdp = scsicmd->sd;
55752889Sbostic 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
55852889Sbostic 	int s;
55952889Sbostic 
56052889Sbostic 	s = splbio();
56152889Sbostic 	/*
56252889Sbostic 	 * Check if another command is already in progress.
56352889Sbostic 	 * We may have to change this if we allow SCSI devices with
56452889Sbostic 	 * separate LUNs.
56552889Sbostic 	 */
56652889Sbostic 	if (asc->cmd[sdp->sd_drive]) {
56752889Sbostic 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
56852889Sbostic 			sdp->sd_driver->d_name);
56952889Sbostic 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
57052889Sbostic 			scsicmd->buflen, 0);
57152889Sbostic 		splx(s);
57252889Sbostic 	}
57352889Sbostic 	asc->cmd[sdp->sd_drive] = scsicmd;
57452889Sbostic 	asc_startcmd(asc, sdp->sd_drive);
57552889Sbostic 	splx(s);
57652889Sbostic }
57752889Sbostic 
57852889Sbostic static void
asc_reset(asc,regs)57952889Sbostic asc_reset(asc, regs)
58052889Sbostic 	asc_softc_t asc;
58152889Sbostic 	asc_regmap_t *regs;
58252889Sbostic {
58352889Sbostic 
58452889Sbostic 	/*
58552889Sbostic 	 * Reset chip and wait till done
58652889Sbostic 	 */
58752889Sbostic 	regs->asc_cmd = ASC_CMD_RESET;
58852889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
58952889Sbostic 
59052889Sbostic 	/* spec says this is needed after reset */
59152889Sbostic 	regs->asc_cmd = ASC_CMD_NOP;
59252889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
59352889Sbostic 
59452889Sbostic 	/*
59552889Sbostic 	 * Set up various chip parameters
59652889Sbostic 	 */
59756819Sralph 	regs->asc_ccf = asc->ccf;
59852889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
59956819Sralph 	regs->asc_sel_timo = asc->timeout_250;
60052889Sbostic 	/* restore our ID */
60152889Sbostic 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
60257233Sralph 	/* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
60357233Sralph 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
60452889Sbostic 	regs->asc_cnfg3 = 0;
60552889Sbostic 	/* zero anything else */
60652889Sbostic 	ASC_TC_PUT(regs, 0);
60756819Sralph 	regs->asc_syn_p = asc->min_period;
60852889Sbostic 	regs->asc_syn_o = 0;	/* async for now */
60952889Sbostic 	MachEmptyWriteBuffer();
61052889Sbostic }
61152889Sbostic 
61252889Sbostic /*
61352889Sbostic  * Start a SCSI command on a target.
61452889Sbostic  */
61552889Sbostic static void
asc_startcmd(asc,target)61652889Sbostic asc_startcmd(asc, target)
61752889Sbostic 	asc_softc_t asc;
61852889Sbostic 	int target;
61952889Sbostic {
62052889Sbostic 	register asc_regmap_t *regs;
62152889Sbostic 	register ScsiCmd *scsicmd;
62252889Sbostic 	register State *state;
62352889Sbostic 	int len;
62452889Sbostic 
62552889Sbostic 	/*
62652889Sbostic 	 * See if another target is currently selected on this SCSI bus.
62752889Sbostic 	 */
62852889Sbostic 	if (asc->target >= 0)
62952889Sbostic 		return;
63052889Sbostic 
63152889Sbostic 	regs = asc->regs;
63252889Sbostic 
63352889Sbostic 	/*
63458658Sralph 	 * If a reselection is in progress, it is Ok to ignore it since
63558658Sralph 	 * the ASC will automatically cancel the command and flush
63658658Sralph 	 * the FIFO if the ASC is reselected before the command starts.
63758658Sralph 	 * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if
63858658Sralph 	 * a reselect occurs before starting the command.
63952889Sbostic 	 */
64052889Sbostic 
64152889Sbostic 	asc->state = ASC_STATE_BUSY;
64252889Sbostic 	asc->target = target;
64352889Sbostic 
64452889Sbostic 	/* cache some pointers */
64552889Sbostic 	scsicmd = asc->cmd[target];
64652889Sbostic 	state = &asc->st[target];
64752889Sbostic 
64852889Sbostic #ifdef DEBUG
64952889Sbostic 	if (asc_debug > 1) {
65052889Sbostic 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
65152889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
65252889Sbostic 			scsicmd->cmd[0], scsicmd->buflen);
65352889Sbostic 	}
65452889Sbostic #endif
65552889Sbostic 
65652889Sbostic 	/*
65752889Sbostic 	 * Init the chip and target state.
65852889Sbostic 	 */
65953080Sralph 	state->flags = state->flags & DID_SYNC;
66052889Sbostic 	state->error = 0;
66152889Sbostic 	state->script = (script_t *)0;
66252889Sbostic 	state->msg_out = SCSI_NO_OP;
66352889Sbostic 
66452889Sbostic 	/*
66552889Sbostic 	 * Copy command data to the DMA buffer.
66652889Sbostic 	 */
66760301Sralph 	len = scsicmd->cmdlen;
66852889Sbostic 	state->dmalen = len;
66960301Sralph 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
67052889Sbostic 
67152889Sbostic 	/* check for simple SCSI command with no data transfer */
67252889Sbostic 	if ((state->buflen = scsicmd->buflen) == 0) {
67352889Sbostic 		/* check for sync negotiation */
67452889Sbostic 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
67552889Sbostic 		    !(state->flags & DID_SYNC)) {
67652889Sbostic 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
67752889Sbostic 			state->flags |= TRY_SYNC;
67852889Sbostic 		} else
67952889Sbostic 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
68052889Sbostic 		state->buf = (char *)0;
68152889Sbostic 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
68252889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
68353080Sralph 		state->buf = scsicmd->buf;
68452889Sbostic 		state->flags |= DMA_OUT;
68552889Sbostic 	} else {
68652889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
68752889Sbostic 		state->buf = scsicmd->buf;
68852889Sbostic 		state->flags |= DMA_IN;
68952889Sbostic 	}
69052889Sbostic 
69158792Sralph #ifdef DEBUG
69258792Sralph 	asc_debug_cmd = scsicmd->cmd[0];
69358792Sralph 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
69458792Sralph 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
69558792Sralph 			(scsicmd->cmd[3] << 16) |
69658792Sralph 			(scsicmd->cmd[4] << 8) |
69758792Sralph 			scsicmd->cmd[5];
69858792Sralph 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
69958792Sralph 	}
70058792Sralph 	asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd);
70158792Sralph 	asc_logp->target = asc->target;
70258792Sralph 	asc_logp->state = asc->script - asc_scripts;
70358792Sralph 	asc_logp->msg = SCSI_DIS_REC_IDENTIFY;
70458792Sralph 	asc_logp->resid = scsicmd->buflen;
70558792Sralph 	if (++asc_logp >= &asc_log[NLOG])
70658792Sralph 		asc_logp = asc_log;
70758792Sralph #endif
70852889Sbostic 
70960301Sralph 	/* preload the FIFO with the message to be sent */
71060301Sralph 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
71160301Sralph 	MachEmptyWriteBuffer();
71260301Sralph 
71358792Sralph 	/* initialize the DMA */
71456819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
71552889Sbostic 	ASC_TC_PUT(regs, len);
71656819Sralph 	readback(regs->asc_cmd);
71752889Sbostic 
71852889Sbostic 	regs->asc_dbus_id = target;
71956819Sralph 	readback(regs->asc_dbus_id);
72052889Sbostic 	regs->asc_syn_p = state->sync_period;
72156819Sralph 	readback(regs->asc_syn_p);
72252889Sbostic 	regs->asc_syn_o = state->sync_offset;
72356819Sralph 	readback(regs->asc_syn_o);
72452889Sbostic 
72552889Sbostic 	if (state->flags & TRY_SYNC)
72653080Sralph 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
72752889Sbostic 	else
72852889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
72956819Sralph 	readback(regs->asc_cmd);
73052889Sbostic }
73152889Sbostic 
73252889Sbostic /*
73352889Sbostic  * Interrupt routine
73452889Sbostic  *	Take interrupts from the chip
73552889Sbostic  *
73652889Sbostic  * Implementation:
73752889Sbostic  *	Move along the current command's script if
73852889Sbostic  *	all is well, invoke error handler if not.
73952889Sbostic  */
74052889Sbostic void
asc_intr(unit)74152889Sbostic asc_intr(unit)
74252889Sbostic 	int unit;
74352889Sbostic {
74452889Sbostic 	register asc_softc_t asc = &asc_softc[unit];
74552889Sbostic 	register asc_regmap_t *regs = asc->regs;
74652889Sbostic 	register State *state;
74752889Sbostic 	register script_t *scpt;
74852889Sbostic 	register int ss, ir, status;
74952889Sbostic 
75052889Sbostic 	/* collect ephemeral information */
75152889Sbostic 	status = regs->asc_status;
75253080Sralph again:
75352889Sbostic 	ss = regs->asc_ss;
75452889Sbostic 	ir = regs->asc_intr;	/* this resets the previous two */
75552889Sbostic 	scpt = asc->script;
75652889Sbostic 
75752889Sbostic #ifdef DEBUG
75852889Sbostic 	asc_logp->status = PACK(unit, status, ss, ir);
75952889Sbostic 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
76052889Sbostic 	asc_logp->state = scpt - asc_scripts;
76152889Sbostic 	asc_logp->msg = -1;
76258658Sralph 	asc_logp->resid = 0;
76352889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
76452889Sbostic 		asc_logp = asc_log;
76552889Sbostic 	if (asc_debug > 2)
76652889Sbostic 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
76752889Sbostic 			status, ss, ir, scpt - asc_scripts, scpt->condition);
76852889Sbostic #endif
76952889Sbostic 
77052889Sbostic 	/* check the expected state */
77152889Sbostic 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
77252889Sbostic 		/*
77352889Sbostic 		 * Perform the appropriate operation, then proceed.
77452889Sbostic 		 */
77552889Sbostic 		if ((*scpt->action)(asc, status, ss, ir)) {
77652889Sbostic 			regs->asc_cmd = scpt->command;
77756819Sralph 			readback(regs->asc_cmd);
77852889Sbostic 			asc->script = scpt->next;
77952889Sbostic 		}
78052889Sbostic 		goto done;
78152889Sbostic 	}
78252889Sbostic 
78358658Sralph 	/*
78458658Sralph 	 * Check for parity error.
78558658Sralph 	 * Hardware will automatically set ATN
78658658Sralph 	 * to request the device for a MSG_OUT phase.
78758658Sralph 	 */
78858658Sralph 	if (status & ASC_CSR_PE) {
78958658Sralph 		printf("asc%d: SCSI device %d: incomming parity error seen\n",
79058658Sralph 			asc - asc_softc, asc->target);
79158658Sralph 		asc->st[asc->target].flags |= PARITY_ERR;
79258658Sralph 	}
79358658Sralph 
79458658Sralph 	/*
79558658Sralph 	 * Check for gross error.
79658658Sralph 	 * Probably a bug in a device driver.
79758658Sralph 	 */
79858658Sralph 	if (status & ASC_CSR_GE) {
79958658Sralph 		printf("asc%d: SCSI device %d: gross error\n",
80058658Sralph 			asc - asc_softc, asc->target);
80158658Sralph 		goto abort;
80258658Sralph 	}
80358658Sralph 
80452889Sbostic 	/* check for message in or out */
80552889Sbostic 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
80652889Sbostic 		register int len, fifo;
80752889Sbostic 
80852889Sbostic 		state = &asc->st[asc->target];
80952889Sbostic 		switch (ASC_PHASE(status)) {
81053080Sralph 		case ASC_PHASE_DATAI:
81153080Sralph 		case ASC_PHASE_DATAO:
81253080Sralph 			ASC_TC_GET(regs, len);
81353080Sralph 			fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
81453080Sralph 			printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
81553080Sralph 				state->buflen, state->dmalen, len, fifo);
81653080Sralph 			goto abort;
81753080Sralph 
81852889Sbostic 		case ASC_PHASE_MSG_IN:
81952889Sbostic 			break;
82052889Sbostic 
82152889Sbostic 		case ASC_PHASE_MSG_OUT:
82258658Sralph 			/*
82358658Sralph 			 * Check for parity error.
82458658Sralph 			 * Hardware will automatically set ATN
82558658Sralph 			 * to request the device for a MSG_OUT phase.
82658658Sralph 			 */
82758658Sralph 			if (state->flags & PARITY_ERR) {
82858658Sralph 				state->flags &= ~PARITY_ERR;
82958658Sralph 				state->msg_out = SCSI_MESSAGE_PARITY_ERROR;
83058658Sralph 				/* reset message in counter */
83158658Sralph 				state->msglen = 0;
83258658Sralph 			} else
83358658Sralph 				state->msg_out = SCSI_NO_OP;
83452889Sbostic 			regs->asc_fifo = state->msg_out;
83552889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
83656819Sralph 			readback(regs->asc_cmd);
83752889Sbostic 			goto done;
83852889Sbostic 
83952889Sbostic 		case ASC_PHASE_STATUS:
84052889Sbostic 			/* probably an error in the SCSI command */
84152889Sbostic 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
84252889Sbostic 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
84356819Sralph 			readback(regs->asc_cmd);
84452889Sbostic 			goto done;
84552889Sbostic 
84652889Sbostic 		default:
84752889Sbostic 			goto abort;
84852889Sbostic 		}
84952889Sbostic 
85052889Sbostic 		if (state->script)
85152889Sbostic 			goto abort;
85252889Sbostic 
85352889Sbostic 		/* check for DMA in progress */
85452889Sbostic 		ASC_TC_GET(regs, len);
85552889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
85652889Sbostic 		/* flush any data in the FIFO */
85752889Sbostic 		if (fifo) {
85853080Sralph 			if (state->flags & DMA_OUT)
85953080Sralph 				len += fifo;
86053080Sralph 			else if (state->flags & DMA_IN) {
86153080Sralph 				u_char *cp;
86253080Sralph 
86353080Sralph 				printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
86453080Sralph 					state->dmalen, len, fifo); /* XXX */
86553080Sralph 				len += fifo;
86653080Sralph 				cp = state->dmaBufAddr + (state->dmalen - len);
86753080Sralph 				while (fifo-- > 0)
86853080Sralph 					*cp++ = regs->asc_fifo;
86953080Sralph 			} else
87053080Sralph 				printf("asc_intr: dmalen %d len %d fifo %d\n",
87153080Sralph 					state->dmalen, len, fifo); /* XXX */
87252889Sbostic 			regs->asc_cmd = ASC_CMD_FLUSH;
87356819Sralph 			readback(regs->asc_cmd);
87456819Sralph 			DELAY(2);
87552889Sbostic 		}
87665433Smckusick 		if (len && (state->flags & DMA_IN_PROGRESS)) {
87752889Sbostic 			/* save number of bytes still to be sent or received */
87852889Sbostic 			state->dmaresid = len;
87965433Smckusick 			state->flags &= ~DMA_IN_PROGRESS;
88067476Smckusick 			ASC_TC_PUT(regs, 0);
88158792Sralph #ifdef DEBUG
88258792Sralph 			if (asc_logp == asc_log)
88358792Sralph 				asc_log[NLOG - 1].resid = len;
88458792Sralph 			else
88558792Sralph 				asc_logp[-1].resid = len;
88658792Sralph #endif
88752889Sbostic 			/* setup state to resume to */
88858792Sralph 			if (state->flags & DMA_IN) {
88958792Sralph 				/*
89058792Sralph 				 * Since the ASC_CNFG3_SRB bit of the
89158792Sralph 				 * cnfg3 register bit is not set,
89258792Sralph 				 * we just transferred an extra byte.
89358792Sralph 				 * Since we can't resume on an odd byte
89458792Sralph 				 * boundary, we copy the valid data out
89558792Sralph 				 * and resume DMA at the start address.
89658792Sralph 				 */
89758792Sralph 				if (len & 1) {
89858792Sralph 					printf("asc_intr: msg in len %d (fifo %d)\n",
89965433Smckusick 						len, fifo); /* XXX */
90058792Sralph 					len = state->dmalen - len;
90158792Sralph 					goto do_in;
90258792Sralph 				}
90352889Sbostic 				state->script =
90452889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
90558792Sralph 			} else if (state->flags & DMA_OUT)
90652889Sbostic 				state->script =
90752889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
90852889Sbostic 			else
90952889Sbostic 				state->script = asc->script;
91065433Smckusick 		} else if (state->flags & DMA_IN) {
91167476Smckusick 			if (len) {
91267476Smckusick 				printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
91367476Smckusick 					asc_debug_bn, len, fifo); /* XXX */
91467476Smckusick 				goto abort;
91567476Smckusick 			}
91652889Sbostic 			/* setup state to resume to */
91765433Smckusick 			if (state->flags & DMA_IN_PROGRESS) {
91865433Smckusick 				len = state->dmalen;
91965433Smckusick 				state->flags &= ~DMA_IN_PROGRESS;
92065433Smckusick 			do_in:
92165433Smckusick 				(*asc->dma_end)(asc, state, ASCDMA_READ);
92265433Smckusick 				bcopy(state->dmaBufAddr, state->buf, len);
92365433Smckusick 				state->buf += len;
92465433Smckusick 				state->buflen -= len;
92565433Smckusick 			}
92665433Smckusick 			if (state->buflen)
92753080Sralph 				state->script =
92865433Smckusick 				    &asc_scripts[SCRIPT_RESUME_IN];
92953080Sralph 			else
93065433Smckusick 				state->script =
93165433Smckusick 				    &asc_scripts[SCRIPT_RESUME_NO_DATA];
93265433Smckusick 		} else if (state->flags & DMA_OUT) {
93367476Smckusick 			if (len) {
93465433Smckusick 				printf("asc_intr: 2: len %d (fifo %d)\n", len,
93565433Smckusick 					fifo); /* XXX */
93667476Smckusick 				goto abort;
93767476Smckusick 			}
93865433Smckusick 			/*
93965433Smckusick 			 * If this is the last chunk, the next expected
94065433Smckusick 			 * state is to get status.
94165433Smckusick 			 */
94265433Smckusick 			if (state->flags & DMA_IN_PROGRESS) {
94365433Smckusick 				state->flags &= ~DMA_IN_PROGRESS;
94465433Smckusick 				(*asc->dma_end)(asc, state, ASCDMA_WRITE);
94565433Smckusick 				len = state->dmalen;
94665433Smckusick 				state->buf += len;
94765433Smckusick 				state->buflen -= len;
94865433Smckusick 			}
94965433Smckusick 			if (state->buflen)
95065433Smckusick 				state->script =
95165433Smckusick 				    &asc_scripts[SCRIPT_RESUME_OUT];
95265433Smckusick 			else
95365433Smckusick 				state->script =
95465433Smckusick 				    &asc_scripts[SCRIPT_RESUME_NO_DATA];
95565433Smckusick 		} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
95665433Smckusick 			state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];
95765433Smckusick 		else
95865433Smckusick 			state->script = asc->script;
95952889Sbostic 
96052889Sbostic 		/* setup to receive a message */
96152889Sbostic 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
96252889Sbostic 		state->msglen = 0;
96352889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO;
96456819Sralph 		readback(regs->asc_cmd);
96552889Sbostic 		goto done;
96652889Sbostic 	}
96752889Sbostic 
96852889Sbostic 	/* check for SCSI bus reset */
96952889Sbostic 	if (ir & ASC_INT_RESET) {
97052889Sbostic 		register int i;
97152889Sbostic 
97252889Sbostic 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
97352889Sbostic 		/* need to flush any pending commands */
97452889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
97552889Sbostic 			if (!asc->cmd[i])
97652889Sbostic 				continue;
97752889Sbostic 			asc->st[i].error = EIO;
97852889Sbostic 			asc_end(asc, 0, 0, 0);
97952889Sbostic 		}
98052889Sbostic 		/* rearbitrate synchronous offset */
98152889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
98252889Sbostic 			asc->st[i].sync_offset = 0;
98352889Sbostic 			asc->st[i].flags = 0;
98452889Sbostic 		}
98552889Sbostic 		asc->target = -1;
98652889Sbostic 		return;
98752889Sbostic 	}
98852889Sbostic 
98952889Sbostic 	/* check for command errors */
99052889Sbostic 	if (ir & ASC_INT_ILL)
99152889Sbostic 		goto abort;
99252889Sbostic 
99352889Sbostic 	/* check for disconnect */
99452889Sbostic 	if (ir & ASC_INT_DISC) {
99552889Sbostic 		state = &asc->st[asc->target];
996*68011Smckusick 		switch (asc->script - asc_scripts) {
997*68011Smckusick 		case SCRIPT_DONE:
998*68011Smckusick 		case SCRIPT_DISCONNECT:
999*68011Smckusick 			/*
1000*68011Smckusick 			 * Disconnects can happen normally when the
1001*68011Smckusick 			 * command is complete with the phase being
1002*68011Smckusick 			 * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN.
1003*68011Smckusick 			 * The SCRIPT_MATCH() only checks for one phase
1004*68011Smckusick 			 * so we can wind up here.
1005*68011Smckusick 			 * Perform the appropriate operation, then proceed.
1006*68011Smckusick 			 */
1007*68011Smckusick 			if ((*scpt->action)(asc, status, ss, ir)) {
1008*68011Smckusick 				regs->asc_cmd = scpt->command;
1009*68011Smckusick 				readback(regs->asc_cmd);
1010*68011Smckusick 				asc->script = scpt->next;
1011*68011Smckusick 			}
1012*68011Smckusick 			goto done;
1013*68011Smckusick 
1014*68011Smckusick 		case SCRIPT_TRY_SYNC:
1015*68011Smckusick 		case SCRIPT_SIMPLE:
1016*68011Smckusick 		case SCRIPT_DATA_IN:
1017*68011Smckusick 		case SCRIPT_DATA_OUT: /* one of the starting scripts */
1018*68011Smckusick 			if (ASC_SS(ss) == 0) {
1019*68011Smckusick 				/* device did not respond */
102058658Sralph 				if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {
102158658Sralph 					regs->asc_cmd = ASC_CMD_FLUSH;
102258658Sralph 					readback(regs->asc_cmd);
102358658Sralph 				}
102458658Sralph 				state->error = ENXIO;
102558658Sralph 				asc_end(asc, status, ss, ir);
102658658Sralph 				return;
102758658Sralph 			}
102858658Sralph 			/* FALLTHROUGH */
102952889Sbostic 
103052889Sbostic 		default:
103158658Sralph 			printf("asc%d: SCSI device %d: unexpected disconnect\n",
103258658Sralph 				asc - asc_softc, asc->target);
1033*68011Smckusick #ifdef DEBUG
1034*68011Smckusick 			asc_DumpLog("asc_disc");
1035*68011Smckusick #endif
103657233Sralph 			/*
103757233Sralph 			 * On rare occasions my RZ24 does a disconnect during
103857233Sralph 			 * data in phase and the following seems to keep it
103957233Sralph 			 * happy.
104057233Sralph 			 * XXX Should a scsi disk ever do this??
104157233Sralph 			 */
104257233Sralph 			asc->script = &asc_scripts[SCRIPT_RESEL];
104357233Sralph 			asc->state = ASC_STATE_RESEL;
104457233Sralph 			state->flags |= DISCONN;
104557233Sralph 			regs->asc_cmd = ASC_CMD_ENABLE_SEL;
104657233Sralph 			readback(regs->asc_cmd);
104757233Sralph 			return;
104852889Sbostic 		}
104952889Sbostic 	}
105052889Sbostic 
105152889Sbostic 	/* check for reselect */
105252889Sbostic 	if (ir & ASC_INT_RESEL) {
105352889Sbostic 		unsigned fifo, id, msg;
105452889Sbostic 
105552889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
105652889Sbostic 		if (fifo < 2)
105752889Sbostic 			goto abort;
105852889Sbostic 		/* read unencoded SCSI ID and convert to binary */
105952889Sbostic 		msg = regs->asc_fifo & asc->myidmask;
106052889Sbostic 		for (id = 0; (msg & 1) == 0; id++)
106152889Sbostic 			msg >>= 1;
106252889Sbostic 		/* read identify message */
106352889Sbostic 		msg = regs->asc_fifo;
106452889Sbostic #ifdef DEBUG
106552889Sbostic 		if (asc_logp == asc_log)
106652889Sbostic 			asc_log[NLOG - 1].msg = msg;
106752889Sbostic 		else
106852889Sbostic 			asc_logp[-1].msg = msg;
106952889Sbostic #endif
107052889Sbostic 		asc->state = ASC_STATE_BUSY;
107152889Sbostic 		asc->target = id;
107252889Sbostic 		state = &asc->st[id];
107352889Sbostic 		asc->script = state->script;
107452889Sbostic 		state->script = (script_t *)0;
107552889Sbostic 		if (!(state->flags & DISCONN))
107652889Sbostic 			goto abort;
107752889Sbostic 		state->flags &= ~DISCONN;
107853080Sralph 		regs->asc_syn_p = state->sync_period;
107953080Sralph 		regs->asc_syn_o = state->sync_offset;
108052889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
108156819Sralph 		readback(regs->asc_cmd);
108252889Sbostic 		goto done;
108352889Sbostic 	}
108452889Sbostic 
108552889Sbostic 	/* check if we are being selected as a target */
108652889Sbostic 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
108752889Sbostic 		goto abort;
108852889Sbostic 
108958658Sralph 	/*
109058658Sralph 	 * 'ir' must be just ASC_INT_FC.
109158658Sralph 	 * This is normal if canceling an ASC_ENABLE_SEL.
109258658Sralph 	 */
109358658Sralph 
109452889Sbostic done:
109552889Sbostic 	MachEmptyWriteBuffer();
109653080Sralph 	/* watch out for HW race conditions and setup & hold time violations */
109753080Sralph 	ir = regs->asc_status;
109853080Sralph 	while (ir != (status = regs->asc_status))
109953080Sralph 		ir = status;
110053080Sralph 	if (status & ASC_CSR_INT)
110152889Sbostic 		goto again;
110252889Sbostic 	return;
110352889Sbostic 
110452889Sbostic abort:
110552889Sbostic #ifdef DEBUG
110652889Sbostic 	asc_DumpLog("asc_intr");
110752889Sbostic #endif
110852889Sbostic #if 0
110952889Sbostic 	panic("asc_intr");
111052889Sbostic #else
111167476Smckusick 	boot(4); /* XXX */
111252889Sbostic #endif
111352889Sbostic }
111452889Sbostic 
111552889Sbostic /*
111652889Sbostic  * All the many little things that the interrupt
111752889Sbostic  * routine might switch to.
111852889Sbostic  */
111952889Sbostic 
112052889Sbostic /* ARGSUSED */
112152889Sbostic static int
script_nop(asc,status,ss,ir)112252889Sbostic script_nop(asc, status, ss, ir)
112352889Sbostic 	register asc_softc_t asc;
112452889Sbostic 	register int status, ss, ir;
112552889Sbostic {
112652889Sbostic 	return (1);
112752889Sbostic }
112852889Sbostic 
112952889Sbostic /* ARGSUSED */
113052889Sbostic static int
asc_get_status(asc,status,ss,ir)113152889Sbostic asc_get_status(asc, status, ss, ir)
113252889Sbostic 	register asc_softc_t asc;
113352889Sbostic 	register int status, ss, ir;
113452889Sbostic {
113552889Sbostic 	register asc_regmap_t *regs = asc->regs;
113652889Sbostic 	register int data;
113752889Sbostic 
113852889Sbostic 	/*
113952889Sbostic 	 * Get the last two bytes in the FIFO.
114052889Sbostic 	 */
114152889Sbostic 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
114252889Sbostic 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
114367797Smckusick #ifdef DEBUG
114458658Sralph 		asc_DumpLog("get_status"); /* XXX */
114567797Smckusick #endif
114652889Sbostic 		if (data < 2) {
114752889Sbostic 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
114856819Sralph 			readback(asc->regs->asc_cmd);
114952889Sbostic 			return (0);
115052889Sbostic 		}
115152889Sbostic 		do {
115252889Sbostic 			data = regs->asc_fifo;
115352889Sbostic 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
115452889Sbostic 	}
115552889Sbostic 
115652889Sbostic 	/* save the status byte */
115752889Sbostic 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
115852889Sbostic #ifdef DEBUG
115952889Sbostic 	if (asc_logp == asc_log)
116052889Sbostic 		asc_log[NLOG - 1].msg = data;
116152889Sbostic 	else
116252889Sbostic 		asc_logp[-1].msg = data;
116352889Sbostic #endif
116452889Sbostic 
116552889Sbostic 	/* get the (presumed) command_complete message */
116652889Sbostic 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
116752889Sbostic 		return (1);
116852889Sbostic 
116952889Sbostic #ifdef DEBUG
117052889Sbostic 	printf("asc_get_status: status %x cmd %x\n",
117152889Sbostic 		asc->st[asc->target].statusByte, data);
117252889Sbostic 	asc_DumpLog("asc_get_status");
117352889Sbostic #endif
117452889Sbostic 	return (0);
117552889Sbostic }
117652889Sbostic 
117752889Sbostic /* ARGSUSED */
117852889Sbostic static int
asc_end(asc,status,ss,ir)117952889Sbostic asc_end(asc, status, ss, ir)
118052889Sbostic 	register asc_softc_t asc;
118152889Sbostic 	register int status, ss, ir;
118252889Sbostic {
118352889Sbostic 	register ScsiCmd *scsicmd;
118452889Sbostic 	register State *state;
118552889Sbostic 	register int i, target;
118652889Sbostic 
118752889Sbostic 	asc->state = ASC_STATE_IDLE;
118852889Sbostic 	target = asc->target;
118952889Sbostic 	asc->target = -1;
119052889Sbostic 	scsicmd = asc->cmd[target];
119152889Sbostic 	asc->cmd[target] = (ScsiCmd *)0;
119252889Sbostic 	state = &asc->st[target];
119352889Sbostic 
119452889Sbostic #ifdef DEBUG
119552889Sbostic 	if (asc_debug > 1) {
119652889Sbostic 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
119752889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
119852889Sbostic 			scsicmd->cmd[0], state->error, state->buflen);
119952889Sbostic 	}
120052889Sbostic #endif
120152889Sbostic #ifdef DIAGNOSTIC
120252889Sbostic 	if (target < 0 || !scsicmd)
120352889Sbostic 		panic("asc_end");
120452889Sbostic #endif
120552889Sbostic 
120652889Sbostic 	/* look for disconnected devices */
120752889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
120852889Sbostic 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
120952889Sbostic 			continue;
121052889Sbostic 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
121156819Sralph 		readback(asc->regs->asc_cmd);
121252889Sbostic 		asc->state = ASC_STATE_RESEL;
121352889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESEL];
121452889Sbostic 		break;
121552889Sbostic 	}
121652889Sbostic 
121758658Sralph 	/*
121858658Sralph 	 * Look for another device that is ready.
121958658Sralph 	 * May want to keep last one started and increment for fairness
122058658Sralph 	 * rather than always starting at zero.
122158658Sralph 	 */
122252889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
122352889Sbostic 		/* don't restart a disconnected command */
122452889Sbostic 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
122552889Sbostic 			continue;
122652889Sbostic 		asc_startcmd(asc, i);
122752889Sbostic 		break;
122852889Sbostic 	}
122952889Sbostic 
123052889Sbostic 	/* signal device driver that the command is done */
123152889Sbostic 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
123252889Sbostic 		state->buflen, state->statusByte);
123352889Sbostic 
123452889Sbostic 	return (0);
123552889Sbostic }
123652889Sbostic 
123752889Sbostic /* ARGSUSED */
123852889Sbostic static int
asc_dma_in(asc,status,ss,ir)123952889Sbostic asc_dma_in(asc, status, ss, ir)
124052889Sbostic 	register asc_softc_t asc;
124152889Sbostic 	register int status, ss, ir;
124252889Sbostic {
124352889Sbostic 	register asc_regmap_t *regs = asc->regs;
124452889Sbostic 	register State *state = &asc->st[asc->target];
124553080Sralph 	register int len;
124652889Sbostic 
124752889Sbostic 	/* check for previous chunk in buffer */
124853080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
124952889Sbostic 		/*
125052889Sbostic 		 * Only count bytes that have been copied to memory.
125152889Sbostic 		 * There may be some bytes in the FIFO if synchonous transfers
125252889Sbostic 		 * are in progress.
125352889Sbostic 		 */
125456819Sralph 		(*asc->dma_end)(asc, state, ASCDMA_READ);
125552889Sbostic 		ASC_TC_GET(regs, len);
125652889Sbostic 		len = state->dmalen - len;
125752889Sbostic 		bcopy(state->dmaBufAddr, state->buf, len);
125852889Sbostic 		state->buf += len;
125952889Sbostic 		state->buflen -= len;
126053080Sralph 	}
126152889Sbostic 
126252942Sralph 	/* setup to start reading the next chunk */
126352889Sbostic 	len = state->buflen;
126467476Smckusick #ifdef DEBUG
126567476Smckusick 	if (asc_logp == asc_log)
126667476Smckusick 		asc_log[NLOG - 1].resid = len;
126767476Smckusick 	else
126867476Smckusick 		asc_logp[-1].resid = len;
126967476Smckusick #endif
127052889Sbostic 	if (len > state->dmaBufSize)
127152889Sbostic 		len = state->dmaBufSize;
127252889Sbostic 	state->dmalen = len;
127356819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
127452889Sbostic 	ASC_TC_PUT(regs, len);
127552942Sralph #ifdef DEBUG
127652942Sralph 	if (asc_debug > 2)
127752942Sralph 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
127852942Sralph #endif
127952942Sralph 
128052942Sralph 	/* check for next chunk */
128153080Sralph 	state->flags |= DMA_IN_PROGRESS;
128252889Sbostic 	if (len != state->buflen) {
128352889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
128456819Sralph 		readback(regs->asc_cmd);
128552942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
128652889Sbostic 		return (0);
128752889Sbostic 	}
128852889Sbostic 	return (1);
128952889Sbostic }
129052889Sbostic 
129152889Sbostic /* ARGSUSED */
129252889Sbostic static int
asc_last_dma_in(asc,status,ss,ir)129352889Sbostic asc_last_dma_in(asc, status, ss, ir)
129452889Sbostic 	register asc_softc_t asc;
129552889Sbostic 	register int status, ss, ir;
129652889Sbostic {
129752889Sbostic 	register asc_regmap_t *regs = asc->regs;
129852889Sbostic 	register State *state = &asc->st[asc->target];
129952889Sbostic 	register int len, fifo;
130052889Sbostic 
130152889Sbostic 	/* copy data from buffer to main memory */
130256819Sralph 	(*asc->dma_end)(asc, state, ASCDMA_READ);
130352889Sbostic 	ASC_TC_GET(regs, len);
130452889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
130552889Sbostic #ifdef DEBUG
130652942Sralph 	if (asc_debug > 2)
130752889Sbostic 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
130852889Sbostic 			state->buflen, state->dmalen, len, fifo);
130952889Sbostic #endif
131052889Sbostic 	if (fifo) {
131152942Sralph 		/* device must be trying to send more than we expect */
131252889Sbostic 		regs->asc_cmd = ASC_CMD_FLUSH;
131356819Sralph 		readback(regs->asc_cmd);
131452889Sbostic 	}
131553080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
131652889Sbostic 	len = state->dmalen - len;
131752889Sbostic 	state->buflen -= len;
131852889Sbostic 	bcopy(state->dmaBufAddr, state->buf, len);
131952889Sbostic 
132052889Sbostic 	return (1);
132152889Sbostic }
132252889Sbostic 
132352889Sbostic /* ARGSUSED */
132452889Sbostic static int
asc_resume_in(asc,status,ss,ir)132552942Sralph asc_resume_in(asc, status, ss, ir)
132652942Sralph 	register asc_softc_t asc;
132752942Sralph 	register int status, ss, ir;
132852942Sralph {
132952942Sralph 	register asc_regmap_t *regs = asc->regs;
133052942Sralph 	register State *state = &asc->st[asc->target];
133152942Sralph 	register int len;
133252942Sralph 
133352942Sralph 	/* setup to start reading the next chunk */
133452942Sralph 	len = state->buflen;
133567476Smckusick #ifdef DEBUG
133667476Smckusick 	if (asc_logp == asc_log)
133767476Smckusick 		asc_log[NLOG - 1].resid = len;
133867476Smckusick 	else
133967476Smckusick 		asc_logp[-1].resid = len;
134067476Smckusick #endif
134152942Sralph 	if (len > state->dmaBufSize)
134252942Sralph 		len = state->dmaBufSize;
134352942Sralph 	state->dmalen = len;
134456819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
134552942Sralph 	ASC_TC_PUT(regs, len);
134652942Sralph #ifdef DEBUG
134752942Sralph 	if (asc_debug > 2)
134852942Sralph 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
134952942Sralph 			len);
135052942Sralph #endif
135152942Sralph 
135252942Sralph 	/* check for next chunk */
135353080Sralph 	state->flags |= DMA_IN_PROGRESS;
135452942Sralph 	if (len != state->buflen) {
135552942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
135656819Sralph 		readback(regs->asc_cmd);
135752942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
135852942Sralph 		return (0);
135952942Sralph 	}
136052942Sralph 	return (1);
136152942Sralph }
136252942Sralph 
136352942Sralph /* ARGSUSED */
136452942Sralph static int
asc_resume_dma_in(asc,status,ss,ir)136552889Sbostic asc_resume_dma_in(asc, status, ss, ir)
136652889Sbostic 	register asc_softc_t asc;
136752889Sbostic 	register int status, ss, ir;
136852889Sbostic {
136952889Sbostic 	register asc_regmap_t *regs = asc->regs;
137052889Sbostic 	register State *state = &asc->st[asc->target];
137152889Sbostic 	register int len, off;
137252889Sbostic 
137352889Sbostic 	/* setup to finish reading the current chunk */
137452889Sbostic 	len = state->dmaresid;
137552889Sbostic 	off = state->dmalen - len;
137652889Sbostic 	if ((off & 1) && state->sync_offset) {
137752889Sbostic 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
137852889Sbostic 			state->dmalen, len, off); /* XXX */
137952889Sbostic 		regs->asc_res_fifo = state->dmaBufAddr[off];
138052889Sbostic 	}
138167476Smckusick #ifdef DEBUG
138267476Smckusick 	if (asc_logp == asc_log)
138367476Smckusick 		asc_log[NLOG - 1].resid = len;
138467476Smckusick 	else
138567476Smckusick 		asc_logp[-1].resid = len;
138667476Smckusick #endif
138756819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
138852889Sbostic 	ASC_TC_PUT(regs, len);
138952942Sralph #ifdef DEBUG
139052942Sralph 	if (asc_debug > 2)
139152942Sralph 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
139252942Sralph 			state->dmalen, state->buflen, len, off);
139352942Sralph #endif
139452942Sralph 
139552942Sralph 	/* check for next chunk */
139653080Sralph 	state->flags |= DMA_IN_PROGRESS;
139752889Sbostic 	if (state->dmalen != state->buflen) {
139852889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
139956819Sralph 		readback(regs->asc_cmd);
140052942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
140152889Sbostic 		return (0);
140252889Sbostic 	}
140352889Sbostic 	return (1);
140452889Sbostic }
140552889Sbostic 
140652889Sbostic /* ARGSUSED */
140752889Sbostic static int
asc_dma_out(asc,status,ss,ir)140852889Sbostic asc_dma_out(asc, status, ss, ir)
140952889Sbostic 	register asc_softc_t asc;
141052889Sbostic 	register int status, ss, ir;
141152889Sbostic {
141252889Sbostic 	register asc_regmap_t *regs = asc->regs;
141352889Sbostic 	register State *state = &asc->st[asc->target];
141452889Sbostic 	register int len, fifo;
141552889Sbostic 
141653080Sralph 	if (state->flags & DMA_IN_PROGRESS) {
141752889Sbostic 		/* check to be sure previous chunk was finished */
141852889Sbostic 		ASC_TC_GET(regs, len);
141952889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
142052889Sbostic 		if (len || fifo)
142152889Sbostic 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
142252889Sbostic 				state->buflen, state->dmalen, len, fifo); /* XXX */
142352889Sbostic 		len += fifo;
142452889Sbostic 		len = state->dmalen - len;
142553080Sralph 		state->buf += len;
142652889Sbostic 		state->buflen -= len;
142753080Sralph 	}
142852889Sbostic 
142958792Sralph 	/* setup for this chunk */
143053080Sralph 	len = state->buflen;
143167476Smckusick #ifdef DEBUG
143267476Smckusick 	if (asc_logp == asc_log)
143367476Smckusick 		asc_log[NLOG - 1].resid = len;
143467476Smckusick 	else
143567476Smckusick 		asc_logp[-1].resid = len;
143667476Smckusick #endif
143753080Sralph 	if (len > state->dmaBufSize)
143853080Sralph 		len = state->dmaBufSize;
143953080Sralph 	state->dmalen = len;
144053080Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
144156819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
144252942Sralph 	ASC_TC_PUT(regs, len);
144352889Sbostic #ifdef DEBUG
144452889Sbostic 	if (asc_debug > 2)
144552942Sralph 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
144652889Sbostic #endif
144752889Sbostic 
144852889Sbostic 	/* check for next chunk */
144953080Sralph 	state->flags |= DMA_IN_PROGRESS;
145052889Sbostic 	if (len != state->buflen) {
145152889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
145256819Sralph 		readback(regs->asc_cmd);
145352942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
145452889Sbostic 		return (0);
145552889Sbostic 	}
145652889Sbostic 	return (1);
145752889Sbostic }
145852889Sbostic 
145952889Sbostic /* ARGSUSED */
146052889Sbostic static int
asc_last_dma_out(asc,status,ss,ir)146152889Sbostic asc_last_dma_out(asc, status, ss, ir)
146252889Sbostic 	register asc_softc_t asc;
146352889Sbostic 	register int status, ss, ir;
146452889Sbostic {
146552889Sbostic 	register asc_regmap_t *regs = asc->regs;
146652889Sbostic 	register State *state = &asc->st[asc->target];
146752889Sbostic 	register int len, fifo;
146852889Sbostic 
146952889Sbostic 	ASC_TC_GET(regs, len);
147052889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
147152889Sbostic #ifdef DEBUG
147252889Sbostic 	if (asc_debug > 2)
147352889Sbostic 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
147453080Sralph 			state->buflen, state->dmalen, len, fifo);
147552942Sralph #endif
147652942Sralph 	if (fifo) {
147752942Sralph 		len += fifo;
147852942Sralph 		regs->asc_cmd = ASC_CMD_FLUSH;
147956819Sralph 		readback(regs->asc_cmd);
148058792Sralph 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
148158792Sralph 			state->buflen, state->dmalen, len, fifo);
148252942Sralph 	}
148353080Sralph 	state->flags &= ~DMA_IN_PROGRESS;
148452889Sbostic 	len = state->dmalen - len;
148552889Sbostic 	state->buflen -= len;
148652889Sbostic 	return (1);
148752889Sbostic }
148852889Sbostic 
148952889Sbostic /* ARGSUSED */
149052889Sbostic static int
asc_resume_out(asc,status,ss,ir)149152942Sralph asc_resume_out(asc, status, ss, ir)
149252942Sralph 	register asc_softc_t asc;
149352942Sralph 	register int status, ss, ir;
149452942Sralph {
149552942Sralph 	register asc_regmap_t *regs = asc->regs;
149652942Sralph 	register State *state = &asc->st[asc->target];
149752942Sralph 	register int len;
149852942Sralph 
149958792Sralph 	/* setup for this chunk */
150052942Sralph 	len = state->buflen;
150167476Smckusick #ifdef DEBUG
150267476Smckusick 	if (asc_logp == asc_log)
150367476Smckusick 		asc_log[NLOG - 1].resid = len;
150467476Smckusick 	else
150567476Smckusick 		asc_logp[-1].resid = len;
150667476Smckusick #endif
150752942Sralph 	if (len > state->dmaBufSize)
150852942Sralph 		len = state->dmaBufSize;
150952942Sralph 	state->dmalen = len;
151052942Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
151156819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
151252942Sralph 	ASC_TC_PUT(regs, len);
151352942Sralph #ifdef DEBUG
151452942Sralph 	if (asc_debug > 2)
151552942Sralph 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
151652942Sralph 			len);
151752942Sralph #endif
151852942Sralph 
151952942Sralph 	/* check for next chunk */
152053080Sralph 	state->flags |= DMA_IN_PROGRESS;
152152942Sralph 	if (len != state->buflen) {
152252942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
152356819Sralph 		readback(regs->asc_cmd);
152452942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
152552942Sralph 		return (0);
152652942Sralph 	}
152752942Sralph 	return (1);
152852942Sralph }
152952942Sralph 
153052942Sralph /* ARGSUSED */
153152942Sralph static int
asc_resume_dma_out(asc,status,ss,ir)153252889Sbostic asc_resume_dma_out(asc, status, ss, ir)
153352889Sbostic 	register asc_softc_t asc;
153452889Sbostic 	register int status, ss, ir;
153552889Sbostic {
153652889Sbostic 	register asc_regmap_t *regs = asc->regs;
153752889Sbostic 	register State *state = &asc->st[asc->target];
153852889Sbostic 	register int len, off;
153952889Sbostic 
154052889Sbostic 	/* setup to finish writing this chunk */
154152889Sbostic 	len = state->dmaresid;
154252889Sbostic 	off = state->dmalen - len;
154352889Sbostic 	if (off & 1) {
154452889Sbostic 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
154552889Sbostic 			state->dmalen, len, off); /* XXX */
154652889Sbostic 		regs->asc_fifo = state->dmaBufAddr[off];
154752889Sbostic 		off++;
154852889Sbostic 		len--;
154952889Sbostic 	}
155067476Smckusick #ifdef DEBUG
155167476Smckusick 	if (asc_logp == asc_log)
155267476Smckusick 		asc_log[NLOG - 1].resid = len;
155367476Smckusick 	else
155467476Smckusick 		asc_logp[-1].resid = len;
155567476Smckusick #endif
155656819Sralph 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
155752889Sbostic 	ASC_TC_PUT(regs, len);
155852942Sralph #ifdef DEBUG
155952942Sralph 	if (asc_debug > 2)
156052942Sralph 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
156152942Sralph 			state->dmalen, state->buflen, len, off);
156252942Sralph #endif
156352942Sralph 
156452942Sralph 	/* check for next chunk */
156553080Sralph 	state->flags |= DMA_IN_PROGRESS;
156652889Sbostic 	if (state->dmalen != state->buflen) {
156752889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
156856819Sralph 		readback(regs->asc_cmd);
156952942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
157052889Sbostic 		return (0);
157152889Sbostic 	}
157252889Sbostic 	return (1);
157352889Sbostic }
157452889Sbostic 
157552889Sbostic /* ARGSUSED */
157652889Sbostic static int
asc_sendsync(asc,status,ss,ir)157752889Sbostic asc_sendsync(asc, status, ss, ir)
157852889Sbostic 	register asc_softc_t asc;
157952889Sbostic 	register int status, ss, ir;
158052889Sbostic {
158152889Sbostic 	register asc_regmap_t *regs = asc->regs;
158253080Sralph 	register State *state = &asc->st[asc->target];
158352889Sbostic 
158453080Sralph 	/* send the extended synchronous negotiation message */
158552889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
158652889Sbostic 	MachEmptyWriteBuffer();
158752889Sbostic 	regs->asc_fifo = 3;
158852889Sbostic 	MachEmptyWriteBuffer();
158952889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
159052889Sbostic 	MachEmptyWriteBuffer();
159152889Sbostic 	regs->asc_fifo = SCSI_MIN_PERIOD;
159252889Sbostic 	MachEmptyWriteBuffer();
159352889Sbostic 	regs->asc_fifo = ASC_MAX_OFFSET;
159453080Sralph 	/* state to resume after we see the sync reply message */
159553080Sralph 	state->script = asc->script + 2;
159653080Sralph 	state->msglen = 0;
159752889Sbostic 	return (1);
159852889Sbostic }
159952889Sbostic 
160052889Sbostic /* ARGSUSED */
160152889Sbostic static int
asc_replysync(asc,status,ss,ir)160252889Sbostic asc_replysync(asc, status, ss, ir)
160352889Sbostic 	register asc_softc_t asc;
160452889Sbostic 	register int status, ss, ir;
160552889Sbostic {
160652889Sbostic 	register asc_regmap_t *regs = asc->regs;
160752889Sbostic 	register State *state = &asc->st[asc->target];
160852889Sbostic 
160952889Sbostic #ifdef DEBUG
161052889Sbostic 	if (asc_debug > 2)
161152889Sbostic 		printf("asc_replysync: %x %x\n",
161256819Sralph 			asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
161352889Sbostic 			state->sync_offset);
161452889Sbostic #endif
161552889Sbostic 	/* send synchronous transfer in response to a request */
161652889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
161752889Sbostic 	MachEmptyWriteBuffer();
161852889Sbostic 	regs->asc_fifo = 3;
161952889Sbostic 	MachEmptyWriteBuffer();
162052889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
162152889Sbostic 	MachEmptyWriteBuffer();
162256819Sralph 	regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
162352889Sbostic 	MachEmptyWriteBuffer();
162452889Sbostic 	regs->asc_fifo = state->sync_offset;
162552889Sbostic 	regs->asc_cmd = ASC_CMD_XFER_INFO;
162656819Sralph 	readback(regs->asc_cmd);
162752889Sbostic 
162852889Sbostic 	/* return to the appropriate script */
162952889Sbostic 	if (!state->script) {
163052889Sbostic #ifdef DEBUG
163152889Sbostic 		asc_DumpLog("asc_replsync");
163252889Sbostic #endif
163352889Sbostic 		panic("asc_replysync");
163452889Sbostic 	}
163552889Sbostic 	asc->script = state->script;
163652889Sbostic 	state->script = (script_t *)0;
163752889Sbostic 	return (0);
163852889Sbostic }
163952889Sbostic 
164052889Sbostic /* ARGSUSED */
164152889Sbostic static int
asc_msg_in(asc,status,ss,ir)164252942Sralph asc_msg_in(asc, status, ss, ir)
164352889Sbostic 	register asc_softc_t asc;
164452889Sbostic 	register int status, ss, ir;
164552889Sbostic {
164652889Sbostic 	register asc_regmap_t *regs = asc->regs;
164752889Sbostic 	register State *state = &asc->st[asc->target];
164852889Sbostic 	register int msg;
164952889Sbostic 	int i;
165052889Sbostic 
165152889Sbostic 	/* read one message byte */
165252889Sbostic 	msg = regs->asc_fifo;
165352889Sbostic #ifdef DEBUG
165452889Sbostic 	if (asc_logp == asc_log)
165552889Sbostic 		asc_log[NLOG - 1].msg = msg;
165652889Sbostic 	else
165752889Sbostic 		asc_logp[-1].msg = msg;
165852889Sbostic #endif
165952889Sbostic 
166052889Sbostic 	/* check for multi-byte message */
166152889Sbostic 	if (state->msglen != 0) {
166252889Sbostic 		/* first byte is the message length */
166352889Sbostic 		if (state->msglen < 0) {
166452889Sbostic 			state->msglen = msg;
166552889Sbostic 			return (1);
166652889Sbostic 		}
166752889Sbostic 		if (state->msgcnt >= state->msglen)
166852889Sbostic 			goto abort;
166952889Sbostic 		state->msg_in[state->msgcnt++] = msg;
167052889Sbostic 
167152889Sbostic 		/* did we just read the last byte of the message? */
167252889Sbostic 		if (state->msgcnt != state->msglen)
167352889Sbostic 			return (1);
167452889Sbostic 
167552889Sbostic 		/* process an extended message */
167652889Sbostic #ifdef DEBUG
167752889Sbostic 		if (asc_debug > 2)
167852942Sralph 			printf("asc_msg_in: msg %x %x %x\n",
167952889Sbostic 				state->msg_in[0],
168052889Sbostic 				state->msg_in[1],
168152889Sbostic 				state->msg_in[2]);
168252889Sbostic #endif
168352889Sbostic 		switch (state->msg_in[0]) {
168452889Sbostic 		case SCSI_SYNCHRONOUS_XFER:
168552889Sbostic 			state->flags |= DID_SYNC;
168652889Sbostic 			state->sync_offset = state->msg_in[2];
168752889Sbostic 
168852889Sbostic 			/* convert SCSI period to ASC period */
168956819Sralph 			i = state->msg_in[1] / asc->tb_ticks;
169056819Sralph 			if (i < asc->min_period)
169156819Sralph 				i = asc->min_period;
169256819Sralph 			else if (i >= asc->max_period) {
169352889Sbostic 				/* can't do sync transfer, period too long */
169452889Sbostic 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
169552889Sbostic 					asc - asc_softc, asc->target, i);
169656819Sralph 				i = asc->max_period;
169752889Sbostic 				state->sync_offset = 0;
169852889Sbostic 			}
169956819Sralph 			if ((i * asc->tb_ticks) != state->msg_in[1])
170052889Sbostic 				i++;
170152889Sbostic 			state->sync_period = i & 0x1F;
170252889Sbostic 
170352889Sbostic 			/*
170452889Sbostic 			 * If this is a request, check minimums and
170552889Sbostic 			 * send back an acknowledge.
170652889Sbostic 			 */
170752889Sbostic 			if (!(state->flags & TRY_SYNC)) {
170852889Sbostic 				regs->asc_cmd = ASC_CMD_SET_ATN;
170956819Sralph 				readback(regs->asc_cmd);
171052889Sbostic 
171156819Sralph 				if (state->sync_period < asc->min_period)
171252889Sbostic 					state->sync_period =
171356819Sralph 						asc->min_period;
171452889Sbostic 				if (state->sync_offset > ASC_MAX_OFFSET)
171552889Sbostic 					state->sync_offset =
171652889Sbostic 						ASC_MAX_OFFSET;
171752889Sbostic 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
171852889Sbostic 				regs->asc_syn_p = state->sync_period;
171956819Sralph 				readback(regs->asc_syn_p);
172052889Sbostic 				regs->asc_syn_o = state->sync_offset;
172156819Sralph 				readback(regs->asc_syn_o);
172252889Sbostic 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
172356819Sralph 				readback(regs->asc_cmd);
172452889Sbostic 				return (0);
172552889Sbostic 			}
172652889Sbostic 
172752889Sbostic 			regs->asc_syn_p = state->sync_period;
172856819Sralph 			readback(regs->asc_syn_p);
172952889Sbostic 			regs->asc_syn_o = state->sync_offset;
173056819Sralph 			readback(regs->asc_syn_o);
173152889Sbostic 			goto done;
173252889Sbostic 
173352889Sbostic 		default:
173452889Sbostic 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
173552889Sbostic 				asc - asc_softc, asc->target,
173652889Sbostic 				state->msg_in[0]);
173752889Sbostic 			goto reject;
173852889Sbostic 		}
173952889Sbostic 	}
174052889Sbostic 
174152889Sbostic 	/* process first byte of a message */
174252889Sbostic #ifdef DEBUG
174352889Sbostic 	if (asc_debug > 2)
174452942Sralph 		printf("asc_msg_in: msg %x\n", msg);
174552889Sbostic #endif
174652889Sbostic 	switch (msg) {
174752889Sbostic #if 0
174852889Sbostic 	case SCSI_MESSAGE_REJECT:
174952889Sbostic 		printf(" did not like SYNCH xfer "); /* XXX */
175052889Sbostic 		state->flags |= DID_SYNC;
175152889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
175256819Sralph 		readback(regs->asc_cmd);
175352889Sbostic 		status = asc_wait(regs, ASC_CSR_INT);
175452889Sbostic 		ir = regs->asc_intr;
175552889Sbostic 		/* some just break out here, some dont */
175652889Sbostic 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
175752889Sbostic 			regs->asc_fifo = SCSI_ABORT;
175852889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
175956819Sralph 			readback(regs->asc_cmd);
176052889Sbostic 			status = asc_wait(regs, ASC_CSR_INT);
176152889Sbostic 			ir = regs->asc_intr;
176252889Sbostic 		}
176352889Sbostic 		if (ir & ASC_INT_DISC) {
176452889Sbostic 			asc_end(asc, status, 0, ir);
176552889Sbostic 			return (0);
176652889Sbostic 		}
176752889Sbostic 		goto status;
176852889Sbostic #endif
176952889Sbostic 
177052889Sbostic 	case SCSI_EXTENDED_MSG: /* read an extended message */
177152889Sbostic 		/* setup to read message length next */
177252889Sbostic 		state->msglen = -1;
177352889Sbostic 		state->msgcnt = 0;
177452889Sbostic 		return (1);
177552889Sbostic 
177652889Sbostic 	case SCSI_NO_OP:
177752889Sbostic 		break;
177852889Sbostic 
177952889Sbostic 	case SCSI_SAVE_DATA_POINTER:
178052889Sbostic 		/* expect another message */
178152889Sbostic 		return (1);
178252889Sbostic 
178352889Sbostic 	case SCSI_RESTORE_POINTERS:
178452889Sbostic 		/*
178552889Sbostic 		 * Need to do the following if resuming synchonous data in
178652889Sbostic 		 * on an odd byte boundary.
178752889Sbostic 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
178852889Sbostic 		 */
178952889Sbostic 		break;
179052889Sbostic 
179152889Sbostic 	case SCSI_DISCONNECT:
179252889Sbostic 		if (state->flags & DISCONN)
179352889Sbostic 			goto abort;
179452889Sbostic 		state->flags |= DISCONN;
179552942Sralph 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
179656819Sralph 		readback(regs->asc_cmd);
179752942Sralph 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
179852942Sralph 		return (0);
179952889Sbostic 
180052889Sbostic 	default:
180152889Sbostic 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
180252889Sbostic 			asc - asc_softc, asc->target, msg);
180352889Sbostic 	reject:
180452889Sbostic 		/* request a message out before acknowledging this message */
180552889Sbostic 		state->msg_out = SCSI_MESSAGE_REJECT;
180652889Sbostic 		regs->asc_cmd = ASC_CMD_SET_ATN;
180756819Sralph 		readback(regs->asc_cmd);
180852889Sbostic 	}
180952889Sbostic 
181052889Sbostic done:
181152889Sbostic 	/* return to original script */
181252889Sbostic 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
181356819Sralph 	readback(regs->asc_cmd);
181452889Sbostic 	if (!state->script) {
181552889Sbostic 	abort:
181652889Sbostic #ifdef DEBUG
181752942Sralph 		asc_DumpLog("asc_msg_in");
181852889Sbostic #endif
181952942Sralph 		panic("asc_msg_in");
182052889Sbostic 	}
182152889Sbostic 	asc->script = state->script;
182252889Sbostic 	state->script = (script_t *)0;
182352889Sbostic 	return (0);
182452889Sbostic }
182552889Sbostic 
182652942Sralph /* ARGSUSED */
182752942Sralph static int
asc_disconnect(asc,status,ss,ir)182852942Sralph asc_disconnect(asc, status, ss, ir)
182952942Sralph 	register asc_softc_t asc;
183052942Sralph 	register int status, ss, ir;
183152942Sralph {
183252942Sralph 	register State *state = &asc->st[asc->target];
183352942Sralph 
183458658Sralph #ifdef DIAGNOSTIC
183558658Sralph 	if (!(state->flags & DISCONN)) {
183658658Sralph 		printf("asc_disconnect: device %d: DISCONN not set!\n",
183758658Sralph 			asc->target);
183858658Sralph 	}
183958658Sralph #endif
184052942Sralph 	asc->target = -1;
184152942Sralph 	asc->state = ASC_STATE_RESEL;
184252942Sralph 	return (1);
184352942Sralph }
184452942Sralph 
184556819Sralph /*
184658792Sralph  * DMA handling routines. For a turbochannel device, just set the dmar.
184758792Sralph  * For the I/O ASIC, handle the actual DMA interface.
184856819Sralph  */
184956819Sralph static void
tb_dma_start(asc,state,cp,flag)185056819Sralph tb_dma_start(asc, state, cp, flag)
185156819Sralph 	asc_softc_t asc;
185256819Sralph 	State *state;
185356819Sralph 	caddr_t cp;
185456819Sralph 	int flag;
185556819Sralph {
185656819Sralph 
185756819Sralph 	if (flag == ASCDMA_WRITE)
185856819Sralph 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
185956819Sralph 	else
186056819Sralph 		*asc->dmar = ASC_DMA_ADDR(cp);
186156819Sralph }
186256819Sralph 
186356819Sralph static void
tb_dma_end(asc,state,flag)186456819Sralph tb_dma_end(asc, state, flag)
186556819Sralph 	asc_softc_t asc;
186656819Sralph 	State *state;
186756819Sralph 	int flag;
186856819Sralph {
186956819Sralph 
187056819Sralph }
187156819Sralph 
187256819Sralph static void
asic_dma_start(asc,state,cp,flag)187356819Sralph asic_dma_start(asc, state, cp, flag)
187456819Sralph 	asc_softc_t asc;
187556819Sralph 	State *state;
187656819Sralph 	caddr_t cp;
187756819Sralph 	int flag;
187856819Sralph {
187956819Sralph 	register volatile u_int *ssr = (volatile u_int *)
188057233Sralph 		ASIC_REG_CSR(asic_base);
188156819Sralph 	u_int phys, nphys;
188256819Sralph 
188356819Sralph 	/* stop DMA engine first */
188456819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
188558658Sralph 	*((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
188656819Sralph 
188756819Sralph 	phys = MACH_CACHED_TO_PHYS(cp);
188856819Sralph 	cp = (caddr_t)pmax_trunc_page(cp + NBPG);
188956819Sralph 	nphys = MACH_CACHED_TO_PHYS(cp);
189056819Sralph 
189156819Sralph 	asc->dma_next = cp;
189256819Sralph 	asc->dma_xfer = state->dmalen - (nphys - phys);
189356819Sralph 
189457233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) =
189556819Sralph 		ASIC_DMA_ADDR(phys);
189657233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
189756819Sralph 		ASIC_DMA_ADDR(nphys);
189856819Sralph 	if (flag == ASCDMA_READ)
189956819Sralph 		*ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI;
190056819Sralph 	else
190156819Sralph 		*ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI;
190256819Sralph 	MachEmptyWriteBuffer();
190356819Sralph }
190456819Sralph 
190556819Sralph static void
asic_dma_end(asc,state,flag)190656819Sralph asic_dma_end(asc, state, flag)
190756819Sralph 	asc_softc_t asc;
190856819Sralph 	State *state;
190956819Sralph 	int flag;
191056819Sralph {
191156819Sralph 	register volatile u_int *ssr = (volatile u_int *)
191257233Sralph 		ASIC_REG_CSR(asic_base);
191360301Sralph 	register volatile u_int *dmap = (volatile u_int *)
191460301Sralph 		ASIC_REG_SCSI_DMAPTR(asic_base);
191560301Sralph 	register u_short *to;
191660301Sralph 	register int w;
191756819Sralph 	int nb;
191856819Sralph 
191956819Sralph 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
192060301Sralph 	to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3);
192160301Sralph 	*dmap = -1;
192257233Sralph 	*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
192356819Sralph 	MachEmptyWriteBuffer();
192456819Sralph 
192556819Sralph 	if (flag == ASCDMA_READ) {
192656819Sralph 		MachFlushDCache(MACH_PHYS_TO_CACHED(
192756819Sralph 		    MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
192857233Sralph 		if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) {
192956819Sralph 			/* pick up last upto6 bytes, sigh. */
193056819Sralph 
193156819Sralph 			/* Last byte really xferred is.. */
193257233Sralph 			w = *(int *)ASIC_REG_SCSI_SDR0(asic_base);
193356819Sralph 			*to++ = w;
193456819Sralph 			if (--nb > 0) {
193556819Sralph 				w >>= 16;
193656819Sralph 				*to++ = w;
193756819Sralph 			}
193856819Sralph 			if (--nb > 0) {
193957233Sralph 				w = *(int *)ASIC_REG_SCSI_SDR1(asic_base);
194056819Sralph 				*to++ = w;
194156819Sralph 			}
194256819Sralph 		}
194356819Sralph 	}
194456819Sralph }
194556819Sralph 
194657233Sralph #ifdef notdef
194756819Sralph /*
194856819Sralph  * Called by asic_intr() for scsi dma pointer update interrupts.
194956819Sralph  */
195056819Sralph void
asc_dma_intr()195156819Sralph asc_dma_intr()
195256819Sralph {
195356819Sralph 	asc_softc_t asc = &asc_softc[0];
195456819Sralph 	u_int next_phys;
195556819Sralph 
195656819Sralph 	asc->dma_xfer -= NBPG;
195756819Sralph 	if (asc->dma_xfer <= -NBPG) {
195856819Sralph 		volatile u_int *ssr = (volatile u_int *)
195957233Sralph 			ASIC_REG_CSR(asic_base);
196056819Sralph 		*ssr &= ~ASIC_CSR_DMAEN_SCSI;
196156819Sralph 	} else {
196256819Sralph 		asc->dma_next += NBPG;
196356819Sralph 		next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
196456819Sralph 	}
196557233Sralph 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
196656819Sralph 		ASIC_DMA_ADDR(next_phys);
196756819Sralph 	MachEmptyWriteBuffer();
196856819Sralph }
196957233Sralph #endif
197056819Sralph 
197152889Sbostic #ifdef DEBUG
asc_DumpLog(str)197252889Sbostic asc_DumpLog(str)
197352889Sbostic 	char *str;
197452889Sbostic {
197552889Sbostic 	register struct asc_log *lp;
197652889Sbostic 	register u_int status;
197752889Sbostic 
197852889Sbostic 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
197952889Sbostic 		asc_debug_bn, asc_debug_sz);
198058570Sralph 	lp = asc_logp;
198158570Sralph 	do {
198252889Sbostic 		status = lp->status;
198358658Sralph 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n",
198452889Sbostic 			status >> 24,
198552889Sbostic 			lp->target,
198652889Sbostic 			(status >> 16) & 0xFF,
198752889Sbostic 			(status >> 8) & 0xFF,
198852889Sbostic 			status & 0XFF,
198952889Sbostic 			lp->state,
199052889Sbostic 			asc_scripts[lp->state].condition,
199158658Sralph 			lp->msg, lp->resid);
199252889Sbostic 		if (++lp >= &asc_log[NLOG])
199352889Sbostic 			lp = asc_log;
199458570Sralph 	} while (lp != asc_logp);
199552889Sbostic }
199652889Sbostic #endif
199752889Sbostic 
199852889Sbostic #endif	/* NASC > 0 */
1999