xref: /csrg-svn/sys/pmax/dev/asc.c (revision 52942)
152889Sbostic /*-
252889Sbostic  * Copyright (c) 1992 The Regents of the University of California.
352889Sbostic  * All rights reserved.
452889Sbostic  *
552889Sbostic  * This code is derived from software contributed to Berkeley by
652889Sbostic  * Ralph Campbell.
752889Sbostic  *
852889Sbostic  * %sccs.include.redist.c%
952889Sbostic  *
10*52942Sralph  *	@(#)asc.c	7.2 (Berkeley) 03/14/92
1152889Sbostic  */
1252889Sbostic 
1352889Sbostic /*
1452889Sbostic  * Mach Operating System
1552889Sbostic  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
1652889Sbostic  * All Rights Reserved.
1752889Sbostic  *
1852889Sbostic  * Permission to use, copy, modify and distribute this software and its
1952889Sbostic  * documentation is hereby granted, provided that both the copyright
2052889Sbostic  * notice and this permission notice appear in all copies of the
2152889Sbostic  * software, derivative works or modified versions, and any portions
2252889Sbostic  * thereof, and that both notices appear in supporting documentation.
2352889Sbostic  *
2452889Sbostic  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
2552889Sbostic  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
2652889Sbostic  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2752889Sbostic  *
2852889Sbostic  * Carnegie Mellon requests users of this software to return to
2952889Sbostic  *
3052889Sbostic  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
3152889Sbostic  *  School of Computer Science
3252889Sbostic  *  Carnegie Mellon University
3352889Sbostic  *  Pittsburgh PA 15213-3890
3452889Sbostic  *
3552889Sbostic  * any improvements or extensions that they make and grant Carnegie the
3652889Sbostic  * rights to redistribute these changes.
3752889Sbostic  */
3852889Sbostic 
3952889Sbostic /*
4052889Sbostic  * HISTORY
4152889Sbostic  * $Log:	scsi_53C94_hdw.c,v $
4252889Sbostic  * Revision 2.5  91/02/05  17:45:07  mrt
4352889Sbostic  * 	Added author notices
4452889Sbostic  * 	[91/02/04  11:18:43  mrt]
4552889Sbostic  *
4652889Sbostic  * 	Changed to use new Mach copyright
4752889Sbostic  * 	[91/02/02  12:17:20  mrt]
4852889Sbostic  *
4952889Sbostic  * Revision 2.4  91/01/08  15:48:24  rpd
5052889Sbostic  * 	Added continuation argument to thread_block.
5152889Sbostic  * 	[90/12/27            rpd]
5252889Sbostic  *
5352889Sbostic  * Revision 2.3  90/12/05  23:34:48  af
5452889Sbostic  * 	Recovered from pmax merge.. and from the destruction of a disk.
5552889Sbostic  * 	[90/12/03  23:40:40  af]
5652889Sbostic  *
5752889Sbostic  * Revision 2.1.1.1  90/11/01  03:39:09  af
5852889Sbostic  * 	Created, from the DEC specs:
5952889Sbostic  * 	"PMAZ-AA TURBOchannel SCSI Module Functional Specification"
6052889Sbostic  * 	Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
6152889Sbostic  * 	And from the NCR data sheets
6252889Sbostic  * 	"NCR 53C94, 53C95, 53C96 Advances SCSI Controller"
6352889Sbostic  * 	[90/09/03            af]
6452889Sbostic  */
6552889Sbostic 
6652889Sbostic /*
6752889Sbostic  *	File: scsi_53C94_hdw.h
6852889Sbostic  * 	Author: Alessandro Forin, Carnegie Mellon University
6952889Sbostic  *	Date:	9/90
7052889Sbostic  *
7152889Sbostic  *	Bottom layer of the SCSI driver: chip-dependent functions
7252889Sbostic  *
7352889Sbostic  *	This file contains the code that is specific to the NCR 53C94
7452889Sbostic  *	SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
7552889Sbostic  *	operation, and interrupt routine.
7652889Sbostic  */
7752889Sbostic 
7852889Sbostic /*
7952889Sbostic  * This layer works based on small simple 'scripts' that are installed
8052889Sbostic  * at the start of the command and drive the chip to completion.
8152889Sbostic  * The idea comes from the specs of the NCR 53C700 'script' processor.
8252889Sbostic  *
8352889Sbostic  * There are various reasons for this, mainly
8452889Sbostic  * - Performance: identify the common (successful) path, and follow it;
8552889Sbostic  *   at interrupt time no code is needed to find the current status
8652889Sbostic  * - Code size: it should be easy to compact common operations
8752889Sbostic  * - Adaptability: the code skeleton should adapt to different chips without
8852889Sbostic  *   terrible complications.
8952889Sbostic  * - Error handling: and it is easy to modify the actions performed
9052889Sbostic  *   by the scripts to cope with strange but well identified sequences
9152889Sbostic  *
9252889Sbostic  */
9352889Sbostic 
9452889Sbostic #include "asc.h"
9552889Sbostic #if NASC > 0
9652889Sbostic 
9752889Sbostic #include "param.h"
9852889Sbostic #include "systm.h"
9952889Sbostic #include "dkstat.h"
10052889Sbostic #include "buf.h"
10152889Sbostic #include "conf.h"
10252889Sbostic #include "errno.h"
10352889Sbostic 
10452889Sbostic #include "device.h"
10552889Sbostic #include "scsi.h"
10652889Sbostic #include "ascreg.h"
10752889Sbostic 
10852889Sbostic #define ASC_OFFSET_53C94	0x0		/* from module base */
10952889Sbostic #define ASC_OFFSET_DMAR		0x40000		/* DMA Address Register */
11052889Sbostic #define ASC_OFFSET_RAM		0x80000		/* SRAM Buffer */
11152889Sbostic #define ASC_OFFSET_ROM		0xc0000		/* Diagnostic ROM */
11252889Sbostic 
11352889Sbostic #define	ASC_RAM_SIZE		0x20000		/* 128k (32k*32) */
11452889Sbostic 
11552889Sbostic /*
11652889Sbostic  * DMA Address Register
11752889Sbostic  */
11852889Sbostic #define ASC_DMAR_MASK		0x1ffff		/* 17 bits, 128k */
11952889Sbostic #define ASC_DMAR_WRITE		0x80000000	/* DMA direction bit */
12052889Sbostic #define	ASC_DMA_ADDR(x)		((unsigned)(x)) & ASC_DMAR_MASK
12152889Sbostic 
12252889Sbostic /*
12352889Sbostic  * Synch xfer parameters, and timing conversions
12452889Sbostic  */
12552889Sbostic #define SCSI_MIN_PERIOD	50	/* in 4 nsecs units */
12652889Sbostic #define ASC_MIN_PERIOD	5	/* in CLKS/BYTE, 1 CLK = 40nsecs */
12752889Sbostic #define ASC_MAX_PERIOD	35	/* in CLKS/BYTE, 1 CLK = 40nsecs */
12852889Sbostic #define ASC_MAX_OFFSET	15	/* pure number */
12952889Sbostic 
13052889Sbostic int	asc_to_scsi_period[] = {
13152889Sbostic 	320,
13252889Sbostic 	330,
13352889Sbostic 	340,
13452889Sbostic 	350,
13552889Sbostic 	50,
13652889Sbostic 	50,
13752889Sbostic 	60,
13852889Sbostic 	70,
13952889Sbostic 	80,
14052889Sbostic 	90,
14152889Sbostic 	100,
14252889Sbostic 	110,
14352889Sbostic 	120,
14452889Sbostic 	130,
14552889Sbostic 	140,
14652889Sbostic 	150,
14752889Sbostic 	160,
14852889Sbostic 	170,
14952889Sbostic 	180,
15052889Sbostic 	190,
15152889Sbostic 	200,
15252889Sbostic 	210,
15352889Sbostic 	220,
15452889Sbostic 	230,
15552889Sbostic 	240,
15652889Sbostic 	250,
15752889Sbostic 	260,
15852889Sbostic 	270,
15952889Sbostic 	280,
16052889Sbostic 	290,
16152889Sbostic 	300,
16252889Sbostic 	310,
16352889Sbostic };
16452889Sbostic 
16552889Sbostic /*
16652889Sbostic  * Internal forward declarations.
16752889Sbostic  */
16852889Sbostic static void asc_reset();
16952889Sbostic static void asc_startcmd();
17052889Sbostic 
17152889Sbostic #ifdef DEBUG
17252889Sbostic int	asc_debug = 1;
17352889Sbostic int	asc_debug_cmd;
17452889Sbostic int	asc_debug_bn;
17552889Sbostic int	asc_debug_sz;
17652889Sbostic #define NLOG 16
17752889Sbostic struct asc_log {
17852889Sbostic 	u_int	status;
17952889Sbostic 	u_char	state;
18052889Sbostic 	u_char	msg;
18152889Sbostic 	int	target;
18252889Sbostic } asc_log[NLOG], *asc_logp = asc_log;
18352889Sbostic #define PACK(unit, status, ss, ir) \
18452889Sbostic 	((unit << 24) | (status << 16) | (ss << 8) | ir)
18552889Sbostic #endif
18652889Sbostic 
18752889Sbostic /*
18852889Sbostic  * Scripts are entries in a state machine table.
18952889Sbostic  * A script has four parts: a pre-condition, an action, a command to the chip,
19052889Sbostic  * and an index into asc_scripts for the next state. The first triggers error
19152889Sbostic  * handling if not satisfied and in our case it is formed by the
19252889Sbostic  * values of the interrupt register and status register, this
19352889Sbostic  * basically captures the phase of the bus and the TC and BS
19452889Sbostic  * bits.  The action part is just a function pointer, and the
19552889Sbostic  * command is what the 53C94 should be told to do at the end
19652889Sbostic  * of the action processing.  This command is only issued and the
19752889Sbostic  * script proceeds if the action routine returns TRUE.
19852889Sbostic  * See asc_intr() for how and where this is all done.
19952889Sbostic  */
20052889Sbostic typedef struct script {
20152889Sbostic 	int		condition;	/* expected state at interrupt time */
20252889Sbostic 	int		(*action)();	/* extra operations */
20352889Sbostic 	int		command;	/* command to the chip */
20452889Sbostic 	struct script	*next;		/* index into asc_scripts for next state */
20552889Sbostic } script_t;
20652889Sbostic 
20752889Sbostic /* Matching on the condition value */
20852889Sbostic #define	SCRIPT_MATCH(ir, csr)		((ir) | (ASC_PHASE(csr) << 8))
20952889Sbostic 
21052889Sbostic /* forward decls of script actions */
21152889Sbostic int	script_nop();			/* when nothing needed */
21252889Sbostic int	asc_end();			/* all come to an end */
21352889Sbostic int	asc_get_status();		/* get status from target */
21452889Sbostic int	asc_dma_in();			/* start reading data from target */
21552889Sbostic int	asc_last_dma_in();		/* cleanup after all data is read */
216*52942Sralph int	asc_resume_in();		/* resume data in after a message */
21752889Sbostic int	asc_resume_dma_in();		/* resume DMA after a disconnect */
21852889Sbostic int	asc_dma_out();			/* send data to target via dma */
21952889Sbostic int	asc_last_dma_out();		/* cleanup after all data is written */
220*52942Sralph int	asc_resume_out();		/* resume data out after a message */
22152889Sbostic int	asc_resume_dma_out();		/* resume DMA after a disconnect */
22252889Sbostic int	asc_sendsync();			/* negotiate sync xfer */
22352889Sbostic int	asc_replysync();		/* negotiate sync xfer */
224*52942Sralph int	asc_msg_in();			/* process a message byte */
225*52942Sralph int	asc_disconnect();		/* process an expected disconnect */
22652889Sbostic 
22752889Sbostic /* Define the index into asc_scripts for various state transitions */
22852889Sbostic #define	SCRIPT_DATA_IN		0
229*52942Sralph #define	SCRIPT_CONTINUE_IN	2
230*52942Sralph #define	SCRIPT_DATA_OUT		3
231*52942Sralph #define	SCRIPT_CONTINUE_OUT	5
232*52942Sralph #define	SCRIPT_SIMPLE		6
233*52942Sralph #define	SCRIPT_GET_STATUS	7
234*52942Sralph #define	SCRIPT_MSG_IN		9
235*52942Sralph #define	SCRIPT_REPLY_SYNC	11
23652889Sbostic #define	SCRIPT_TRY_SYNC		12
237*52942Sralph #define	SCRIPT_DISCONNECT	15
238*52942Sralph #define	SCRIPT_RESEL		16
239*52942Sralph #define	SCRIPT_RESUME_IN	17
240*52942Sralph #define	SCRIPT_RESUME_DMA_IN	18
241*52942Sralph #define	SCRIPT_RESUME_OUT	19
242*52942Sralph #define	SCRIPT_RESUME_DMA_OUT	20
243*52942Sralph #define	SCRIPT_RESUME_NO_DATA	21
24452889Sbostic 
24552889Sbostic /*
24652889Sbostic  * Scripts
24752889Sbostic  */
24852889Sbostic script_t asc_scripts[] = {
249*52942Sralph 	/* start data in */
25052889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
25152889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
252*52942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
25352889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
25452889Sbostic 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
255*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
25652889Sbostic 
257*52942Sralph 	/* continue data in after a chuck is finished */
258*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/*  2 */
259*52942Sralph 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
260*52942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
261*52942Sralph 
262*52942Sralph 	/* start data out */
263*52942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  3 */
26452889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
265*52942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
266*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  4 */
26752889Sbostic 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
268*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
26952889Sbostic 
270*52942Sralph 	/* continue data out after a chuck is finished */
271*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/*  5 */
272*52942Sralph 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
273*52942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
274*52942Sralph 
27552889Sbostic 	/* simple command with no data transfer */
276*52942Sralph 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  6 */
27752889Sbostic 		script_nop, ASC_CMD_I_COMPLETE,
278*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
27952889Sbostic 
28052889Sbostic 	/* get status and finish command */
281*52942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
28252889Sbostic 		asc_get_status, ASC_CMD_MSG_ACPT,
283*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
284*52942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  8 */
28552889Sbostic 		asc_end, ASC_CMD_NOP,
286*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
28752889Sbostic 
28852889Sbostic 	/* message in */
289*52942Sralph 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  9 */
290*52942Sralph 		asc_msg_in, ASC_CMD_MSG_ACPT,
291*52942Sralph 		&asc_scripts[SCRIPT_MSG_IN + 1]},
292*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 10 */
29352889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
294*52942Sralph 		&asc_scripts[SCRIPT_MSG_IN]},
29552889Sbostic 
29652889Sbostic 	/* send synchonous negotiation reply */
297*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/* 11 */
29852889Sbostic 		asc_replysync, ASC_CMD_XFER_INFO,
299*52942Sralph 		&asc_scripts[SCRIPT_REPLY_SYNC]},
30052889Sbostic 
30152889Sbostic 	/* try to negotiate synchonous transfer parameters */
30252889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
30352889Sbostic 		asc_sendsync, ASC_CMD_XFER_INFO,
304*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
30552889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 13 */
30652889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
307*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
30852889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 14 */
309*52942Sralph 		asc_msg_in, ASC_CMD_MSG_ACPT,
310*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
31152889Sbostic 
312*52942Sralph 	/* handle a disconnect */
313*52942Sralph 	{SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO),			/* 15 */
314*52942Sralph 		asc_disconnect, ASC_CMD_ENABLE_SEL,
315*52942Sralph 		&asc_scripts[SCRIPT_RESEL]},
316*52942Sralph 
31752889Sbostic 	/* reselect sequence: this is just a placeholder so match fails */
318*52942Sralph 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 16 */
31952889Sbostic 		script_nop, ASC_CMD_MSG_ACPT,
320*52942Sralph 		&asc_scripts[SCRIPT_RESEL]},
32152889Sbostic 
322*52942Sralph 	/* resume data in after a message */
323*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 17 */
324*52942Sralph 		asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
325*52942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
326*52942Sralph 
327*52942Sralph 	/* resume partial DMA data in after a message */
328*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 18 */
32952889Sbostic 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
330*52942Sralph 		&asc_scripts[SCRIPT_DATA_IN + 1]},
33152889Sbostic 
332*52942Sralph 	/* resume data out after a message */
333*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 19 */
334*52942Sralph 		asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
335*52942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
336*52942Sralph 
337*52942Sralph 	/* resume partial DMA data out after a message */
338*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 20 */
33952889Sbostic 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
340*52942Sralph 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
341*52942Sralph 
342*52942Sralph 	/* resume after a message when there is no more data */
343*52942Sralph 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/* 21 */
344*52942Sralph 		script_nop, ASC_CMD_I_COMPLETE,
345*52942Sralph 		&asc_scripts[SCRIPT_GET_STATUS]},
34652889Sbostic };
34752889Sbostic 
34852889Sbostic /*
34952889Sbostic  * State kept for each active SCSI device.
35052889Sbostic  */
35152889Sbostic typedef struct scsi_state {
35252889Sbostic 	script_t *script;	/* saved script while processing error */
35352889Sbostic 	int	statusByte;	/* status byte returned during STATUS_PHASE */
35452889Sbostic 	int	error;		/* errno to pass back to device driver */
35552889Sbostic 	u_char	*dmaBufAddr;	/* DMA buffer address */
35652889Sbostic 	u_int	dmaBufSize;	/* DMA buffer size */
35752889Sbostic 	int	dmalen;		/* amount to transfer in this chunk */
35852889Sbostic 	int	dmaresid;	/* amount not transfered if chunk suspended */
35952889Sbostic 	int	buflen;		/* total remaining amount of data to transfer */
36052889Sbostic 	char	*buf;		/* current pointer within scsicmd->buf */
36152889Sbostic 	int	flags;		/* see below */
36252889Sbostic 	int	msglen;		/* number of message bytes to read */
36352889Sbostic 	int	msgcnt;		/* number of message bytes received */
36452889Sbostic 	u_char	sync_period;	/* DMA synchronous period */
36552889Sbostic 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
36652889Sbostic 	u_char	msg_out;	/* next MSG_OUT byte to send */
36752889Sbostic 	u_char	msg_in[16];	/* buffer for multibyte messages */
36852889Sbostic } State;
36952889Sbostic 
37052889Sbostic /* state flags */
37152889Sbostic #define DISCONN		0x01	/* true if currently disconnected from bus */
37252889Sbostic #define FIRST_DMA	0x02	/* true if no data DMA started yet */
37352889Sbostic #define DMA_IN		0x04	/* true if reading from SCSI device */
37452889Sbostic #define DMA_OUT		0x10	/* true if writing to SCSI device */
37552889Sbostic #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
37652889Sbostic #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
37752889Sbostic 
37852889Sbostic #define ASC_NCMD	7
37952889Sbostic /*
38052889Sbostic  * State kept for each active SCSI host interface (53C94).
38152889Sbostic  */
38252889Sbostic struct asc_softc {
38352889Sbostic 	asc_regmap_t	*regs;		/* chip address */
38452889Sbostic 	volatile int	*dmar;		/* DMA address register address */
38552889Sbostic 	volatile u_char	*buff;		/* RAM buffer address */
38652889Sbostic 	int		myid;		/* SCSI ID of this interface */
38752889Sbostic 	int		myidmask;	/* ~(1 << myid) */
38852889Sbostic 	int		state;		/* current SCSI connection state */
38952889Sbostic 	int		target;		/* target SCSI ID if busy */
39052889Sbostic 	script_t	*script;	/* next expected interrupt & action */
39152889Sbostic 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
39252889Sbostic 	State		st[ASC_NCMD];	/* state info for each active command */
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 /*
40352889Sbostic  * Definition of the controller for the auto-configuration program.
40452889Sbostic  */
40552889Sbostic int	asc_probe();
40652889Sbostic void	asc_start();
40752889Sbostic void	asc_intr();
40852889Sbostic struct	driver ascdriver = {
40952889Sbostic 	"asc", asc_probe, asc_start, 0, asc_intr,
41052889Sbostic };
41152889Sbostic 
41252889Sbostic /*
41352889Sbostic  * Test to see if device is present.
41452889Sbostic  * Return true if found and initialized ok.
41552889Sbostic  */
41652889Sbostic asc_probe(cp)
41752889Sbostic 	register struct pmax_ctlr *cp;
41852889Sbostic {
41952889Sbostic 	register asc_softc_t asc;
42052889Sbostic 	register asc_regmap_t *regs;
42152889Sbostic 	int unit, id, s, i;
42252889Sbostic 
42352889Sbostic 	if ((unit = cp->pmax_unit) >= NASC)
42452889Sbostic 		return (0);
42552889Sbostic 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
42652889Sbostic 		return (0);
42752889Sbostic 	asc = &asc_softc[unit];
42852889Sbostic 
42952889Sbostic 	/*
43052889Sbostic 	 * Initialize hw descriptor, cache some pointers
43152889Sbostic 	 */
43252889Sbostic 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
43352889Sbostic 	asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
43452889Sbostic 	asc->buff = (volatile u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
43552889Sbostic 
43652889Sbostic 	asc->state = ASC_STATE_IDLE;
43752889Sbostic 	asc->target = -1;
43852889Sbostic 
43952889Sbostic 	regs = asc->regs;
44052889Sbostic 
44152889Sbostic 	/*
44252889Sbostic 	 * Reset chip, fully.  Note that interrupts are already enabled.
44352889Sbostic 	 */
44452889Sbostic 	s = splbio();
44552889Sbostic 
44652889Sbostic 	/* preserve our ID for now */
44752889Sbostic 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
44852889Sbostic 	asc->myidmask = ~(1 << asc->myid);
44952889Sbostic 
45052889Sbostic 	asc_reset(asc, regs);
45152889Sbostic 
45252889Sbostic 	/*
45352889Sbostic 	 * Our SCSI id on the bus.
45452889Sbostic 	 * The user can set this via the prom on 3maxen/pmaxen.
45552889Sbostic 	 * If this changes it is easy to fix: make a default that
45652889Sbostic 	 * can be changed as boot arg.
45752889Sbostic 	 */
45852889Sbostic #ifdef	unneeded
45952889Sbostic 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
46052889Sbostic 			      (scsi_initiator_id[unit] & 0x7);
46152889Sbostic #endif
46252889Sbostic 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
46352889Sbostic 	splx(s);
46452889Sbostic 
46552889Sbostic 	/*
46652889Sbostic 	 * Statically partition the DMA buffer between targets.
46752889Sbostic 	 * This way we will eventually be able to attach/detach
46852889Sbostic 	 * drives on-fly.  And 18k/target is plenty for normal use.
46952889Sbostic 	 */
47052889Sbostic #define PER_TGT_DMA_SIZE	((ASC_RAM_SIZE/7) & ~(sizeof(int)-1))
47152889Sbostic 
47252889Sbostic 	/*
47352889Sbostic 	 * Give each target its own DMA buffer region.
47452889Sbostic 	 * We may want to try ping ponging buffers later.
47552889Sbostic 	 */
47652889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
47752889Sbostic 		asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i;
47852889Sbostic 		asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE;
47952889Sbostic 	}
48052889Sbostic 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
48152889Sbostic 		unit, cp->pmax_addr, cp->pmax_pri, id);
48252889Sbostic 	return (1);
48352889Sbostic }
48452889Sbostic 
48552889Sbostic /*
48652889Sbostic  * Start activity on a SCSI device.
48752889Sbostic  * We maintain information on each device separately since devices can
48852889Sbostic  * connect/disconnect during an operation.
48952889Sbostic  */
49052889Sbostic void
49152889Sbostic asc_start(scsicmd)
49252889Sbostic 	register ScsiCmd *scsicmd;	/* command to start */
49352889Sbostic {
49452889Sbostic 	register struct scsi_device *sdp = scsicmd->sd;
49552889Sbostic 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
49652889Sbostic 	int s;
49752889Sbostic 
49852889Sbostic 	s = splbio();
49952889Sbostic 	/*
50052889Sbostic 	 * Check if another command is already in progress.
50152889Sbostic 	 * We may have to change this if we allow SCSI devices with
50252889Sbostic 	 * separate LUNs.
50352889Sbostic 	 */
50452889Sbostic 	if (asc->cmd[sdp->sd_drive]) {
50552889Sbostic 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
50652889Sbostic 			sdp->sd_driver->d_name);
50752889Sbostic 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
50852889Sbostic 			scsicmd->buflen, 0);
50952889Sbostic 		splx(s);
51052889Sbostic 	}
51152889Sbostic 	asc->cmd[sdp->sd_drive] = scsicmd;
51252889Sbostic 	asc_startcmd(asc, sdp->sd_drive);
51352889Sbostic 	splx(s);
51452889Sbostic }
51552889Sbostic 
51652889Sbostic static void
51752889Sbostic asc_reset(asc, regs)
51852889Sbostic 	asc_softc_t asc;
51952889Sbostic 	asc_regmap_t *regs;
52052889Sbostic {
52152889Sbostic 
52252889Sbostic 	/*
52352889Sbostic 	 * Reset chip and wait till done
52452889Sbostic 	 */
52552889Sbostic 	regs->asc_cmd = ASC_CMD_RESET;
52652889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
52752889Sbostic 
52852889Sbostic 	/* spec says this is needed after reset */
52952889Sbostic 	regs->asc_cmd = ASC_CMD_NOP;
53052889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
53152889Sbostic 
53252889Sbostic 	/*
53352889Sbostic 	 * Set up various chip parameters
53452889Sbostic 	 */
53552889Sbostic 	regs->asc_ccf = ASC_CCF_25MHz;	/* 25 MHz clock */
53652889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
53752889Sbostic 	regs->asc_sel_timo = ASC_TIMEOUT_250;
53852889Sbostic 	/* restore our ID */
53952889Sbostic 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
54052889Sbostic 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_EPL;
54152889Sbostic 	regs->asc_cnfg3 = 0;
54252889Sbostic 	/* zero anything else */
54352889Sbostic 	ASC_TC_PUT(regs, 0);
54452889Sbostic 	regs->asc_sel_timo = ASC_TIMEOUT_250;
54552889Sbostic 	regs->asc_syn_p = ASC_MIN_PERIOD;
54652889Sbostic 	regs->asc_syn_o = 0;	/* async for now */
54752889Sbostic 	MachEmptyWriteBuffer();
54852889Sbostic }
54952889Sbostic 
55052889Sbostic /*
55152889Sbostic  * Start a SCSI command on a target.
55252889Sbostic  */
55352889Sbostic static void
55452889Sbostic asc_startcmd(asc, target)
55552889Sbostic 	asc_softc_t asc;
55652889Sbostic 	int target;
55752889Sbostic {
55852889Sbostic 	register asc_regmap_t *regs;
55952889Sbostic 	register ScsiCmd *scsicmd;
56052889Sbostic 	register State *state;
56152889Sbostic 	int len;
56252889Sbostic 
56352889Sbostic 	/*
56452889Sbostic 	 * See if another target is currently selected on this SCSI bus.
56552889Sbostic 	 */
56652889Sbostic 	if (asc->target >= 0)
56752889Sbostic 		return;
56852889Sbostic 
56952889Sbostic 	regs = asc->regs;
57052889Sbostic 
57152889Sbostic 	/*
57252889Sbostic 	 * Check to see if a reselection is in progress and if so,
57352889Sbostic 	 * try to cancel it or respond to the reselection if it won.
57452889Sbostic 	 */
57552889Sbostic 	if (asc->state == ASC_STATE_RESEL) {
57652889Sbostic 		regs->asc_cmd = ASC_CMD_DISABLE_SEL;
57752889Sbostic 		while (!(regs->asc_status & ASC_CSR_INT))
57852889Sbostic 			DELAY(1);
57952889Sbostic 		asc_intr(asc - asc_softc);
58052889Sbostic 		/* we will be busy if a reselecting device won */
58152889Sbostic 		if (asc->state == ASC_STATE_BUSY)
58252889Sbostic 			return;
58352889Sbostic 	}
58452889Sbostic 
58552889Sbostic 	asc->state = ASC_STATE_BUSY;
58652889Sbostic 	asc->target = target;
58752889Sbostic 
58852889Sbostic 	/* cache some pointers */
58952889Sbostic 	scsicmd = asc->cmd[target];
59052889Sbostic 	state = &asc->st[target];
59152889Sbostic 
59252889Sbostic #ifdef DEBUG
59352889Sbostic 	if (asc_debug > 1) {
59452889Sbostic 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
59552889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
59652889Sbostic 			scsicmd->cmd[0], scsicmd->buflen);
59752889Sbostic 	}
59852889Sbostic 	asc_debug_cmd = scsicmd->cmd[0];
59952889Sbostic 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
60052889Sbostic 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
60152889Sbostic 			(scsicmd->cmd[3] << 16) |
60252889Sbostic 			(scsicmd->cmd[4] << 8) |
60352889Sbostic 			scsicmd->cmd[5];
60452889Sbostic 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
60552889Sbostic 	}
60652889Sbostic 	asc_logp->status = PACK(asc - asc_softc, 0, 0, 0);
60752889Sbostic 	asc_logp->target = asc->target;
60852889Sbostic 	asc_logp->state = 0;
60952889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
61052889Sbostic 		asc_logp = asc_log;
61152889Sbostic #endif
61252889Sbostic 
61352889Sbostic 	/*
61452889Sbostic 	 * Init the chip and target state.
61552889Sbostic 	 */
61652889Sbostic 	regs->asc_cmd = ASC_CMD_FLUSH;
61752889Sbostic 	state->flags = FIRST_DMA | (state->flags & DID_SYNC);
61852889Sbostic 	state->error = 0;
61952889Sbostic 	state->script = (script_t *)0;
62052889Sbostic 	state->msg_out = SCSI_NO_OP;
62152889Sbostic 
62252889Sbostic 	/*
62352889Sbostic 	 * Copy command data to the DMA buffer.
62452889Sbostic 	 */
62552889Sbostic 	len = scsicmd->cmdlen;
62652889Sbostic 	state->dmalen = len;
62752889Sbostic 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
62852889Sbostic 
62952889Sbostic 	/* check for simple SCSI command with no data transfer */
63052889Sbostic 	if ((state->buflen = scsicmd->buflen) == 0) {
63152889Sbostic 		/* check for sync negotiation */
63252889Sbostic 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
63352889Sbostic 		    !(state->flags & DID_SYNC)) {
63452889Sbostic 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
63552889Sbostic 			state->flags |= TRY_SYNC;
63652889Sbostic 		} else
63752889Sbostic 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
63852889Sbostic 		state->buf = (char *)0;
63952889Sbostic 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
64052889Sbostic 		int cnt;
64152889Sbostic 
64252889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
64352889Sbostic 
64452889Sbostic 		/* setup to write first chunk */
64552889Sbostic 		state->flags |= DMA_OUT;
64652889Sbostic 		state->buf = scsicmd->buf;
64752889Sbostic 		cnt = state->dmaBufSize - len;
64852889Sbostic 		if (cnt > state->buflen)
64952889Sbostic 			cnt = state->buflen;
65052889Sbostic 		else printf("can't write in one chunk cnt %d buflen %d\n",
65152889Sbostic 			cnt, state->buflen); /* XXX */
65252889Sbostic 		state->dmalen = cnt;
65352889Sbostic 		bcopy(state->buf, state->dmaBufAddr + len, cnt);
65452889Sbostic 	} else {
65552889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
65652889Sbostic 		state->buf = scsicmd->buf;
65752889Sbostic 		state->flags |= DMA_IN;
65852889Sbostic 	}
65952889Sbostic 
66052889Sbostic 	/* preload the FIFO with the message to be sent */
661*52942Sralph 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
66252889Sbostic 
66352889Sbostic 	/* start the asc */
66452889Sbostic 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
66552889Sbostic 	ASC_TC_PUT(regs, len);
66652889Sbostic 
66752889Sbostic 	regs->asc_dbus_id = target;
66852889Sbostic 	regs->asc_syn_p = state->sync_period;
66952889Sbostic 	regs->asc_syn_o = state->sync_offset;
67052889Sbostic 
67152889Sbostic 	if (state->flags & TRY_SYNC)
67252889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA;
67352889Sbostic 	else
67452889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
67552889Sbostic }
67652889Sbostic 
67752889Sbostic /*
67852889Sbostic  * Interrupt routine
67952889Sbostic  *	Take interrupts from the chip
68052889Sbostic  *
68152889Sbostic  * Implementation:
68252889Sbostic  *	Move along the current command's script if
68352889Sbostic  *	all is well, invoke error handler if not.
68452889Sbostic  */
68552889Sbostic void
68652889Sbostic asc_intr(unit)
68752889Sbostic 	int unit;
68852889Sbostic {
68952889Sbostic 	register asc_softc_t asc = &asc_softc[unit];
69052889Sbostic 	register asc_regmap_t *regs = asc->regs;
69152889Sbostic 	register State *state;
69252889Sbostic 	register script_t *scpt;
69352889Sbostic 	register int ss, ir, status;
69452889Sbostic 
69552889Sbostic again:
69652889Sbostic 	/* collect ephemeral information */
69752889Sbostic 	status = regs->asc_status;
69852889Sbostic 	ss = regs->asc_ss;
69952889Sbostic 	ir = regs->asc_intr;	/* this resets the previous two */
70052889Sbostic 	scpt = asc->script;
70152889Sbostic 
70252889Sbostic #ifdef DEBUG
70352889Sbostic 	asc_logp->status = PACK(unit, status, ss, ir);
70452889Sbostic 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
70552889Sbostic 	asc_logp->state = scpt - asc_scripts;
70652889Sbostic 	asc_logp->msg = -1;
70752889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
70852889Sbostic 		asc_logp = asc_log;
70952889Sbostic 	if (asc_debug > 2)
71052889Sbostic 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
71152889Sbostic 			status, ss, ir, scpt - asc_scripts, scpt->condition);
71252889Sbostic #endif
71352889Sbostic 
71452889Sbostic 	/* check the expected state */
71552889Sbostic 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
71652889Sbostic 		/*
71752889Sbostic 		 * Perform the appropriate operation, then proceed.
71852889Sbostic 		 */
71952889Sbostic 		if ((*scpt->action)(asc, status, ss, ir)) {
72052889Sbostic 			regs->asc_cmd = scpt->command;
72152889Sbostic 			asc->script = scpt->next;
72252889Sbostic 		}
72352889Sbostic 		goto done;
72452889Sbostic 	}
72552889Sbostic 
72652889Sbostic 	/* check for message in or out */
72752889Sbostic 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
72852889Sbostic 		register int len, fifo;
72952889Sbostic 
73052889Sbostic 		state = &asc->st[asc->target];
73152889Sbostic 		switch (ASC_PHASE(status)) {
73252889Sbostic 		case ASC_PHASE_MSG_IN:
73352889Sbostic 			break;
73452889Sbostic 
73552889Sbostic 		case ASC_PHASE_MSG_OUT:
73652889Sbostic 			regs->asc_fifo = state->msg_out;
73752889Sbostic 			state->msg_out = SCSI_NO_OP;
73852889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
73952889Sbostic 			goto done;
74052889Sbostic 
74152889Sbostic 		case ASC_PHASE_STATUS:
742*52942Sralph 			asc_DumpLog("asc_intr: status"); /* XXX */
74352889Sbostic 			/* probably an error in the SCSI command */
74452889Sbostic 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
74552889Sbostic 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
74652889Sbostic 			goto done;
74752889Sbostic 
74852889Sbostic 		default:
74952889Sbostic 			goto abort;
75052889Sbostic 		}
75152889Sbostic 
75252889Sbostic 		if (state->script)
75352889Sbostic 			goto abort;
75452889Sbostic 
75552889Sbostic 		/* check for DMA in progress */
75652889Sbostic 		ASC_TC_GET(regs, len);
75752889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
75852889Sbostic 		/* flush any data in the FIFO */
75952889Sbostic 		if (fifo) {
76052889Sbostic 			printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n",
76152889Sbostic 				state->flags, state->dmalen,
76252889Sbostic 				len, fifo); /* XXX */
76352889Sbostic 			len += fifo;
76452889Sbostic 			regs->asc_cmd = ASC_CMD_FLUSH;
76552889Sbostic 			MachEmptyWriteBuffer();
76652889Sbostic 		}
76752889Sbostic 		if (len) {
76852889Sbostic 			/* save number of bytes still to be sent or received */
76952889Sbostic 			state->dmaresid = len;
77052889Sbostic 			/* setup state to resume to */
77152889Sbostic 			if (state->flags & DMA_IN)
77252889Sbostic 				state->script =
77352889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
77452889Sbostic 			else if (state->flags & DMA_OUT)
77552889Sbostic 				state->script =
77652889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
77752889Sbostic 			else
77852889Sbostic 				state->script = asc->script;
77952889Sbostic 		} else {
78052889Sbostic 			/* setup state to resume to */
781*52942Sralph 			if (state->flags & DMA_IN) {
782*52942Sralph 				if (!(state->flags & FIRST_DMA)) {
783*52942Sralph 					len = state->dmalen;
784*52942Sralph 					bcopy(state->dmaBufAddr, state->buf,
785*52942Sralph 						len);
786*52942Sralph 					state->buf += len;
787*52942Sralph 					state->buflen -= len;
788*52942Sralph 				} else
789*52942Sralph 					state->flags &= ~FIRST_DMA;
790*52942Sralph 				if (state->buflen)
791*52942Sralph 					state->script =
792*52942Sralph 					    &asc_scripts[SCRIPT_RESUME_IN];
793*52942Sralph 				else
794*52942Sralph 					state->script =
795*52942Sralph 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
796*52942Sralph 			} else if (state->flags & DMA_OUT) {
797*52942Sralph 				/*
798*52942Sralph 				 * If this is the last chunk, the next expected
799*52942Sralph 				 * state is to get status.
800*52942Sralph 				 */
801*52942Sralph 				len = state->dmalen;
802*52942Sralph 				state->buf += len;
803*52942Sralph 				state->buflen -= len;
804*52942Sralph 				if (state->buflen)
805*52942Sralph 					state->script =
806*52942Sralph 					    &asc_scripts[SCRIPT_RESUME_OUT];
807*52942Sralph 				else
808*52942Sralph 					state->script =
809*52942Sralph 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
810*52942Sralph 			} else
81152889Sbostic 				state->script = asc->script;
81252889Sbostic 		}
81352889Sbostic 
81452889Sbostic 		/* setup to receive a message */
81552889Sbostic 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
81652889Sbostic 		state->msglen = 0;
81752889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO;
81852889Sbostic 		goto done;
81952889Sbostic 	}
82052889Sbostic 
82152889Sbostic 	/* check for SCSI bus reset */
82252889Sbostic 	if (ir & ASC_INT_RESET) {
82352889Sbostic 		register int i;
82452889Sbostic 
82552889Sbostic 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
82652889Sbostic 		/* need to flush any pending commands */
82752889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
82852889Sbostic 			if (!asc->cmd[i])
82952889Sbostic 				continue;
83052889Sbostic 			asc->st[i].error = EIO;
83152889Sbostic 			asc_end(asc, 0, 0, 0);
83252889Sbostic 		}
83352889Sbostic 		/* rearbitrate synchronous offset */
83452889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
83552889Sbostic 			asc->st[i].sync_offset = 0;
83652889Sbostic 			asc->st[i].flags = 0;
83752889Sbostic 		}
83852889Sbostic 		asc->target = -1;
83952889Sbostic 		return;
84052889Sbostic 	}
84152889Sbostic 
84252889Sbostic 	/* check for command errors */
84352889Sbostic 	if (ir & ASC_INT_ILL)
84452889Sbostic 		goto abort;
84552889Sbostic 
84652889Sbostic 	/* check for disconnect */
84752889Sbostic 	if (ir & ASC_INT_DISC) {
84852889Sbostic 		state = &asc->st[asc->target];
84952889Sbostic 		switch (ASC_SS(ss)) {
85052889Sbostic 		case 0: /* device did not respond */
85152889Sbostic 			state->error = ENXIO;
85252889Sbostic 			asc_end(asc, status, ss, ir);
85352889Sbostic 			return;
85452889Sbostic 
85552889Sbostic 		default:
85652889Sbostic 			goto abort;
85752889Sbostic 		}
85852889Sbostic 	}
85952889Sbostic 
86052889Sbostic 	/* check for reselect */
86152889Sbostic 	if (ir & ASC_INT_RESEL) {
86252889Sbostic 		unsigned fifo, id, msg;
86352889Sbostic 
86452889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
86552889Sbostic 		if (fifo < 2)
86652889Sbostic 			goto abort;
86752889Sbostic 		/* read unencoded SCSI ID and convert to binary */
86852889Sbostic 		msg = regs->asc_fifo & asc->myidmask;
86952889Sbostic 		for (id = 0; (msg & 1) == 0; id++)
87052889Sbostic 			msg >>= 1;
87152889Sbostic 		/* read identify message */
87252889Sbostic 		msg = regs->asc_fifo;
87352889Sbostic #ifdef DEBUG
87452889Sbostic 		if (asc_logp == asc_log)
87552889Sbostic 			asc_log[NLOG - 1].msg = msg;
87652889Sbostic 		else
87752889Sbostic 			asc_logp[-1].msg = msg;
87852889Sbostic #endif
87952889Sbostic 		if (asc->state != ASC_STATE_RESEL)
88052889Sbostic 			goto abort;
88152889Sbostic 		asc->state = ASC_STATE_BUSY;
88252889Sbostic 		asc->target = id;
88352889Sbostic 		state = &asc->st[id];
88452889Sbostic 		asc->script = state->script;
88552889Sbostic 		state->script = (script_t *)0;
88652889Sbostic 		if (!(state->flags & DISCONN))
88752889Sbostic 			goto abort;
88852889Sbostic 		state->flags &= ~DISCONN;
88952889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
89052889Sbostic 		goto done;
89152889Sbostic 	}
89252889Sbostic 
89352889Sbostic 	/* check if we are being selected as a target */
89452889Sbostic 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
89552889Sbostic 		goto abort;
89652889Sbostic 
89752889Sbostic 	/* must be just a ASC_INT_FC */
89852889Sbostic done:
89952889Sbostic 	MachEmptyWriteBuffer();
90052889Sbostic 	if (regs->asc_status & ASC_CSR_INT)
90152889Sbostic 		goto again;
90252889Sbostic 	return;
90352889Sbostic 
90452889Sbostic abort:
90552889Sbostic #ifdef DEBUG
90652889Sbostic 	asc_DumpLog("asc_intr");
90752889Sbostic #endif
90852889Sbostic #if 0
90952889Sbostic 	panic("asc_intr");
91052889Sbostic #else
91152889Sbostic 	for (;;);
91252889Sbostic #endif
91352889Sbostic }
91452889Sbostic 
91552889Sbostic /*
91652889Sbostic  * All the many little things that the interrupt
91752889Sbostic  * routine might switch to.
91852889Sbostic  */
91952889Sbostic 
92052889Sbostic /* ARGSUSED */
92152889Sbostic static int
92252889Sbostic script_nop(asc, status, ss, ir)
92352889Sbostic 	register asc_softc_t asc;
92452889Sbostic 	register int status, ss, ir;
92552889Sbostic {
92652889Sbostic 	return (1);
92752889Sbostic }
92852889Sbostic 
92952889Sbostic /* ARGSUSED */
93052889Sbostic static int
93152889Sbostic asc_get_status(asc, status, ss, ir)
93252889Sbostic 	register asc_softc_t asc;
93352889Sbostic 	register int status, ss, ir;
93452889Sbostic {
93552889Sbostic 	register asc_regmap_t *regs = asc->regs;
93652889Sbostic 	register int data;
93752889Sbostic 
93852889Sbostic 	/*
93952889Sbostic 	 * Get the last two bytes in the FIFO.
94052889Sbostic 	 */
94152889Sbostic 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
94252889Sbostic 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
94352889Sbostic 		if (data < 2) {
94452889Sbostic 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
94552889Sbostic 			return (0);
94652889Sbostic 		}
94752889Sbostic 		do {
94852889Sbostic 			data = regs->asc_fifo;
94952889Sbostic 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
95052889Sbostic 	}
95152889Sbostic 
95252889Sbostic 	/* save the status byte */
95352889Sbostic 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
95452889Sbostic #ifdef DEBUG
95552889Sbostic 	if (asc_logp == asc_log)
95652889Sbostic 		asc_log[NLOG - 1].msg = data;
95752889Sbostic 	else
95852889Sbostic 		asc_logp[-1].msg = data;
95952889Sbostic #endif
96052889Sbostic 
96152889Sbostic 	/* get the (presumed) command_complete message */
96252889Sbostic 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
96352889Sbostic 		return (1);
96452889Sbostic 
96552889Sbostic #ifdef DEBUG
96652889Sbostic 	printf("asc_get_status: status %x cmd %x\n",
96752889Sbostic 		asc->st[asc->target].statusByte, data);
96852889Sbostic 	asc_DumpLog("asc_get_status");
96952889Sbostic #endif
97052889Sbostic 	return (0);
97152889Sbostic }
97252889Sbostic 
97352889Sbostic /* ARGSUSED */
97452889Sbostic static int
97552889Sbostic asc_end(asc, status, ss, ir)
97652889Sbostic 	register asc_softc_t asc;
97752889Sbostic 	register int status, ss, ir;
97852889Sbostic {
97952889Sbostic 	register ScsiCmd *scsicmd;
98052889Sbostic 	register State *state;
98152889Sbostic 	register int i, target;
98252889Sbostic 
98352889Sbostic 	asc->state = ASC_STATE_IDLE;
98452889Sbostic 	target = asc->target;
98552889Sbostic 	asc->target = -1;
98652889Sbostic 	scsicmd = asc->cmd[target];
98752889Sbostic 	asc->cmd[target] = (ScsiCmd *)0;
98852889Sbostic 	state = &asc->st[target];
98952889Sbostic 
99052889Sbostic #ifdef DEBUG
99152889Sbostic 	if (asc_debug > 1) {
99252889Sbostic 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
99352889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
99452889Sbostic 			scsicmd->cmd[0], state->error, state->buflen);
99552889Sbostic 	}
99652889Sbostic #endif
99752889Sbostic #ifdef DIAGNOSTIC
99852889Sbostic 	if (target < 0 || !scsicmd)
99952889Sbostic 		panic("asc_end");
100052889Sbostic #endif
100152889Sbostic 
100252889Sbostic 	/* look for disconnected devices */
100352889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
100452889Sbostic 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
100552889Sbostic 			continue;
100652889Sbostic 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
100752889Sbostic 		asc->state = ASC_STATE_RESEL;
100852889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESEL];
100952889Sbostic 		break;
101052889Sbostic 	}
101152889Sbostic 
101252889Sbostic 	/* look for another device that is ready */
101352889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
101452889Sbostic 		/* don't restart a disconnected command */
101552889Sbostic 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
101652889Sbostic 			continue;
101752889Sbostic 		asc_startcmd(asc, i);
101852889Sbostic 		break;
101952889Sbostic 	}
102052889Sbostic 
102152889Sbostic 	/* signal device driver that the command is done */
102252889Sbostic 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
102352889Sbostic 		state->buflen, state->statusByte);
102452889Sbostic 
102552889Sbostic 	return (0);
102652889Sbostic }
102752889Sbostic 
102852889Sbostic /* ARGSUSED */
102952889Sbostic static int
103052889Sbostic asc_dma_in(asc, status, ss, ir)
103152889Sbostic 	register asc_softc_t asc;
103252889Sbostic 	register int status, ss, ir;
103352889Sbostic {
103452889Sbostic 	register asc_regmap_t *regs = asc->regs;
103552889Sbostic 	register State *state = &asc->st[asc->target];
103652889Sbostic 	register int len, fifo;
103752889Sbostic 
103852889Sbostic 	/* check for previous chunk in buffer */
103952889Sbostic 	if (!(state->flags & FIRST_DMA)) {
104052889Sbostic 		/*
104152889Sbostic 		 * Only count bytes that have been copied to memory.
104252889Sbostic 		 * There may be some bytes in the FIFO if synchonous transfers
104352889Sbostic 		 * are in progress.
104452889Sbostic 		 */
104552889Sbostic 		ASC_TC_GET(regs, len);
104652889Sbostic 		len = state->dmalen - len;
104752889Sbostic 		bcopy(state->dmaBufAddr, state->buf, len);
104852889Sbostic 		state->buf += len;
104952889Sbostic 		state->buflen -= len;
105052889Sbostic 	} else
105152889Sbostic 		state->flags &= ~FIRST_DMA;
105252889Sbostic 
1053*52942Sralph 	/* setup to start reading the next chunk */
105452889Sbostic 	len = state->buflen;
105552889Sbostic 	if (len > state->dmaBufSize)
105652889Sbostic 		len = state->dmaBufSize;
105752889Sbostic 	state->dmalen = len;
105852889Sbostic 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr);
105952889Sbostic 	ASC_TC_PUT(regs, len);
1060*52942Sralph #ifdef DEBUG
1061*52942Sralph 	if (asc_debug > 2)
1062*52942Sralph 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1063*52942Sralph #endif
1064*52942Sralph 
1065*52942Sralph 	/* check for next chunk */
106652889Sbostic 	if (len != state->buflen) {
106752889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1068*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
106952889Sbostic 		return (0);
107052889Sbostic 	}
107152889Sbostic 	return (1);
107252889Sbostic }
107352889Sbostic 
107452889Sbostic /* ARGSUSED */
107552889Sbostic static int
107652889Sbostic asc_last_dma_in(asc, status, ss, ir)
107752889Sbostic 	register asc_softc_t asc;
107852889Sbostic 	register int status, ss, ir;
107952889Sbostic {
108052889Sbostic 	register asc_regmap_t *regs = asc->regs;
108152889Sbostic 	register State *state = &asc->st[asc->target];
108252889Sbostic 	register int len, fifo;
108352889Sbostic 
108452889Sbostic 	/* copy data from buffer to main memory */
108552889Sbostic 	ASC_TC_GET(regs, len);
108652889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
108752889Sbostic #ifdef DEBUG
1088*52942Sralph #if 0
1089*52942Sralph 	if (asc_debug > 2)
1090*52942Sralph #else
109152889Sbostic 	if (asc_debug > 2 || len || fifo) /* XXX */
1092*52942Sralph #endif
109352889Sbostic 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
109452889Sbostic 			state->buflen, state->dmalen, len, fifo);
109552889Sbostic #endif
109652889Sbostic 	if (fifo) {
1097*52942Sralph 		/* device must be trying to send more than we expect */
109852889Sbostic 		regs->asc_cmd = ASC_CMD_FLUSH;
109952889Sbostic 		MachEmptyWriteBuffer();
110052889Sbostic 	}
110152889Sbostic 	len = state->dmalen - len;
110252889Sbostic 	state->buflen -= len;
110352889Sbostic 	bcopy(state->dmaBufAddr, state->buf, len);
110452889Sbostic 
110552889Sbostic 	return (1);
110652889Sbostic }
110752889Sbostic 
110852889Sbostic /* ARGSUSED */
110952889Sbostic static int
1110*52942Sralph asc_resume_in(asc, status, ss, ir)
1111*52942Sralph 	register asc_softc_t asc;
1112*52942Sralph 	register int status, ss, ir;
1113*52942Sralph {
1114*52942Sralph 	register asc_regmap_t *regs = asc->regs;
1115*52942Sralph 	register State *state = &asc->st[asc->target];
1116*52942Sralph 	register int len;
1117*52942Sralph 
1118*52942Sralph 	/* setup to start reading the next chunk */
1119*52942Sralph 	len = state->buflen;
1120*52942Sralph 	if (len > state->dmaBufSize)
1121*52942Sralph 		len = state->dmaBufSize;
1122*52942Sralph 	state->dmalen = len;
1123*52942Sralph 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr);
1124*52942Sralph 	ASC_TC_PUT(regs, len);
1125*52942Sralph #ifdef DEBUG
1126*52942Sralph 	if (asc_debug > 2)
1127*52942Sralph 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1128*52942Sralph 			len);
1129*52942Sralph #endif
1130*52942Sralph 
1131*52942Sralph 	/* check for next chunk */
1132*52942Sralph 	if (len != state->buflen) {
1133*52942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1134*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1135*52942Sralph 		return (0);
1136*52942Sralph 	}
1137*52942Sralph 	return (1);
1138*52942Sralph }
1139*52942Sralph 
1140*52942Sralph /* ARGSUSED */
1141*52942Sralph static int
114252889Sbostic asc_resume_dma_in(asc, status, ss, ir)
114352889Sbostic 	register asc_softc_t asc;
114452889Sbostic 	register int status, ss, ir;
114552889Sbostic {
114652889Sbostic 	register asc_regmap_t *regs = asc->regs;
114752889Sbostic 	register State *state = &asc->st[asc->target];
114852889Sbostic 	register int len, off;
114952889Sbostic 
115052889Sbostic 	/* setup to finish reading the current chunk */
115152889Sbostic 	len = state->dmaresid;
115252889Sbostic 	off = state->dmalen - len;
115352889Sbostic 	if ((off & 1) && state->sync_offset) {
115452889Sbostic 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
115552889Sbostic 			state->dmalen, len, off); /* XXX */
115652889Sbostic 		regs->asc_res_fifo = state->dmaBufAddr[off];
115752889Sbostic 	}
115852889Sbostic 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off);
115952889Sbostic 	ASC_TC_PUT(regs, len);
1160*52942Sralph #ifdef DEBUG
1161*52942Sralph 	if (asc_debug > 2)
1162*52942Sralph 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1163*52942Sralph 			state->dmalen, state->buflen, len, off);
1164*52942Sralph #endif
1165*52942Sralph 
1166*52942Sralph 	/* check for next chunk */
116752889Sbostic 	if (state->dmalen != state->buflen) {
116852889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1169*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
117052889Sbostic 		return (0);
117152889Sbostic 	}
117252889Sbostic 	return (1);
117352889Sbostic }
117452889Sbostic 
117552889Sbostic /* ARGSUSED */
117652889Sbostic static int
117752889Sbostic asc_dma_out(asc, status, ss, ir)
117852889Sbostic 	register asc_softc_t asc;
117952889Sbostic 	register int status, ss, ir;
118052889Sbostic {
118152889Sbostic 	register asc_regmap_t *regs = asc->regs;
118252889Sbostic 	register State *state = &asc->st[asc->target];
118352889Sbostic 	register int len, fifo;
118452889Sbostic 
118552889Sbostic 	if (!(state->flags & FIRST_DMA)) {
118652889Sbostic 		/* check to be sure previous chunk was finished */
118752889Sbostic 		ASC_TC_GET(regs, len);
118852889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
118952889Sbostic 		if (len || fifo)
119052889Sbostic 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
119152889Sbostic 				state->buflen, state->dmalen, len, fifo); /* XXX */
119252889Sbostic 		len += fifo;
119352889Sbostic 		len = state->dmalen - len;
119452889Sbostic 		state->buflen -= len;
119552889Sbostic 		state->buf += len;
119652889Sbostic 
119752889Sbostic 		/* setup for this chunck */
119852889Sbostic 		len = state->buflen;
119952889Sbostic 		if (len > state->dmaBufSize)
120052889Sbostic 			len = state->dmaBufSize;
120152889Sbostic 		state->dmalen = len;
120252889Sbostic 		bcopy(state->buf, state->dmaBufAddr, len);
120352889Sbostic 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
120452889Sbostic 	} else
120552889Sbostic 		state->flags &= ~FIRST_DMA;
120652889Sbostic 
1207*52942Sralph 	len = state->dmalen;
1208*52942Sralph 	ASC_TC_PUT(regs, len);
120952889Sbostic #ifdef DEBUG
121052889Sbostic 	if (asc_debug > 2)
1211*52942Sralph 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
121252889Sbostic #endif
121352889Sbostic 
121452889Sbostic 	/* check for next chunk */
121552889Sbostic 	if (len != state->buflen) {
121652889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1217*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
121852889Sbostic 		return (0);
121952889Sbostic 	}
122052889Sbostic 	return (1);
122152889Sbostic }
122252889Sbostic 
122352889Sbostic /* ARGSUSED */
122452889Sbostic static int
122552889Sbostic asc_last_dma_out(asc, status, ss, ir)
122652889Sbostic 	register asc_softc_t asc;
122752889Sbostic 	register int status, ss, ir;
122852889Sbostic {
122952889Sbostic 	register asc_regmap_t *regs = asc->regs;
123052889Sbostic 	register State *state = &asc->st[asc->target];
123152889Sbostic 	register int len, fifo;
123252889Sbostic 
123352889Sbostic 	ASC_TC_GET(regs, len);
123452889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
123552889Sbostic #ifdef DEBUG
1236*52942Sralph #if 0
123752889Sbostic 	if (asc_debug > 2)
1238*52942Sralph #else
1239*52942Sralph 	if (asc_debug > 2 || len || fifo) /* XXX */
124052889Sbostic #endif
124152889Sbostic 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
124252889Sbostic 			state->buflen, state->dmalen, len, fifo); /* XXX */
1243*52942Sralph #endif
1244*52942Sralph 	if (fifo) {
1245*52942Sralph 		len += fifo;
1246*52942Sralph 		regs->asc_cmd = ASC_CMD_FLUSH;
1247*52942Sralph 		MachEmptyWriteBuffer();
1248*52942Sralph 	}
124952889Sbostic 	len = state->dmalen - len;
125052889Sbostic 	state->buflen -= len;
125152889Sbostic 	return (1);
125252889Sbostic }
125352889Sbostic 
125452889Sbostic /* ARGSUSED */
125552889Sbostic static int
1256*52942Sralph asc_resume_out(asc, status, ss, ir)
1257*52942Sralph 	register asc_softc_t asc;
1258*52942Sralph 	register int status, ss, ir;
1259*52942Sralph {
1260*52942Sralph 	register asc_regmap_t *regs = asc->regs;
1261*52942Sralph 	register State *state = &asc->st[asc->target];
1262*52942Sralph 	register int len;
1263*52942Sralph 
1264*52942Sralph 	/* setup for this chunck */
1265*52942Sralph 	len = state->buflen;
1266*52942Sralph 	if (len > state->dmaBufSize)
1267*52942Sralph 		len = state->dmaBufSize;
1268*52942Sralph 	state->dmalen = len;
1269*52942Sralph 	bcopy(state->buf, state->dmaBufAddr, len);
1270*52942Sralph 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
1271*52942Sralph 	ASC_TC_PUT(regs, len);
1272*52942Sralph #ifdef DEBUG
1273*52942Sralph 	if (asc_debug > 2)
1274*52942Sralph 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1275*52942Sralph 			len);
1276*52942Sralph #endif
1277*52942Sralph 
1278*52942Sralph 	/* check for next chunk */
1279*52942Sralph 	if (len != state->buflen) {
1280*52942Sralph 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1281*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1282*52942Sralph 		return (0);
1283*52942Sralph 	}
1284*52942Sralph 	return (1);
1285*52942Sralph }
1286*52942Sralph 
1287*52942Sralph /* ARGSUSED */
1288*52942Sralph static int
128952889Sbostic asc_resume_dma_out(asc, status, ss, ir)
129052889Sbostic 	register asc_softc_t asc;
129152889Sbostic 	register int status, ss, ir;
129252889Sbostic {
129352889Sbostic 	register asc_regmap_t *regs = asc->regs;
129452889Sbostic 	register State *state = &asc->st[asc->target];
129552889Sbostic 	register int len, off;
129652889Sbostic 
129752889Sbostic 	/* setup to finish writing this chunk */
129852889Sbostic 	len = state->dmaresid;
129952889Sbostic 	off = state->dmalen - len;
130052889Sbostic 	if (off & 1) {
130152889Sbostic 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
130252889Sbostic 			state->dmalen, len, off); /* XXX */
130352889Sbostic 		regs->asc_fifo = state->dmaBufAddr[off];
130452889Sbostic 		off++;
130552889Sbostic 		len--;
130652889Sbostic 	}
130752889Sbostic 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off);
130852889Sbostic 	ASC_TC_PUT(regs, len);
1309*52942Sralph #ifdef DEBUG
1310*52942Sralph 	if (asc_debug > 2)
1311*52942Sralph 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1312*52942Sralph 			state->dmalen, state->buflen, len, off);
1313*52942Sralph #endif
1314*52942Sralph 
1315*52942Sralph 	/* check for next chunk */
131652889Sbostic 	if (state->dmalen != state->buflen) {
131752889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1318*52942Sralph 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
131952889Sbostic 		return (0);
132052889Sbostic 	}
132152889Sbostic 	return (1);
132252889Sbostic }
132352889Sbostic 
132452889Sbostic /* ARGSUSED */
132552889Sbostic static int
132652889Sbostic asc_sendsync(asc, status, ss, ir)
132752889Sbostic 	register asc_softc_t asc;
132852889Sbostic 	register int status, ss, ir;
132952889Sbostic {
133052889Sbostic 	register asc_regmap_t *regs = asc->regs;
133152889Sbostic 
133252889Sbostic 	/*
133352889Sbostic 	 * Phase is MSG_OUT here.
133452889Sbostic 	 * Try sync negotiation, unless prohibited
133552889Sbostic 	 */
133652889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
133752889Sbostic 	MachEmptyWriteBuffer();
133852889Sbostic 	regs->asc_fifo = 3;
133952889Sbostic 	MachEmptyWriteBuffer();
134052889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
134152889Sbostic 	MachEmptyWriteBuffer();
134252889Sbostic 	regs->asc_fifo = SCSI_MIN_PERIOD;
134352889Sbostic 	MachEmptyWriteBuffer();
134452889Sbostic 	regs->asc_fifo = ASC_MAX_OFFSET;
134552889Sbostic 	return (1);
134652889Sbostic }
134752889Sbostic 
134852889Sbostic /* ARGSUSED */
134952889Sbostic static int
135052889Sbostic asc_replysync(asc, status, ss, ir)
135152889Sbostic 	register asc_softc_t asc;
135252889Sbostic 	register int status, ss, ir;
135352889Sbostic {
135452889Sbostic 	register asc_regmap_t *regs = asc->regs;
135552889Sbostic 	register State *state = &asc->st[asc->target];
135652889Sbostic 
135752889Sbostic #ifdef DEBUG
135852889Sbostic 	if (asc_debug > 2)
135952889Sbostic 		printf("asc_replysync: %x %x\n",
136052889Sbostic 			asc_to_scsi_period[state->sync_period],
136152889Sbostic 			state->sync_offset);
136252889Sbostic #endif
136352889Sbostic 	/* send synchronous transfer in response to a request */
136452889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
136552889Sbostic 	MachEmptyWriteBuffer();
136652889Sbostic 	regs->asc_fifo = 3;
136752889Sbostic 	MachEmptyWriteBuffer();
136852889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
136952889Sbostic 	MachEmptyWriteBuffer();
137052889Sbostic 	regs->asc_fifo = asc_to_scsi_period[state->sync_period];
137152889Sbostic 	MachEmptyWriteBuffer();
137252889Sbostic 	regs->asc_fifo = state->sync_offset;
137352889Sbostic 	regs->asc_cmd = ASC_CMD_XFER_INFO;
137452889Sbostic 
137552889Sbostic 	/* return to the appropriate script */
137652889Sbostic 	if (!state->script) {
137752889Sbostic #ifdef DEBUG
137852889Sbostic 		asc_DumpLog("asc_replsync");
137952889Sbostic #endif
138052889Sbostic 		panic("asc_replysync");
138152889Sbostic 	}
138252889Sbostic 	asc->script = state->script;
138352889Sbostic 	state->script = (script_t *)0;
138452889Sbostic 	return (0);
138552889Sbostic }
138652889Sbostic 
138752889Sbostic /* ARGSUSED */
138852889Sbostic static int
1389*52942Sralph asc_msg_in(asc, status, ss, ir)
139052889Sbostic 	register asc_softc_t asc;
139152889Sbostic 	register int status, ss, ir;
139252889Sbostic {
139352889Sbostic 	register asc_regmap_t *regs = asc->regs;
139452889Sbostic 	register State *state = &asc->st[asc->target];
139552889Sbostic 	register int msg;
139652889Sbostic 	int i;
139752889Sbostic 
139852889Sbostic 	/* read one message byte */
139952889Sbostic 	msg = regs->asc_fifo;
140052889Sbostic #ifdef DEBUG
140152889Sbostic 	if (asc_logp == asc_log)
140252889Sbostic 		asc_log[NLOG - 1].msg = msg;
140352889Sbostic 	else
140452889Sbostic 		asc_logp[-1].msg = msg;
140552889Sbostic #endif
140652889Sbostic 
140752889Sbostic 	/* check for multi-byte message */
140852889Sbostic 	if (state->msglen != 0) {
140952889Sbostic 		/* first byte is the message length */
141052889Sbostic 		if (state->msglen < 0) {
141152889Sbostic 			state->msglen = msg;
141252889Sbostic 			return (1);
141352889Sbostic 		}
141452889Sbostic 		if (state->msgcnt >= state->msglen)
141552889Sbostic 			goto abort;
141652889Sbostic 		state->msg_in[state->msgcnt++] = msg;
141752889Sbostic 
141852889Sbostic 		/* did we just read the last byte of the message? */
141952889Sbostic 		if (state->msgcnt != state->msglen)
142052889Sbostic 			return (1);
142152889Sbostic 
142252889Sbostic 		/* process an extended message */
142352889Sbostic #ifdef DEBUG
142452889Sbostic 		if (asc_debug > 2)
1425*52942Sralph 			printf("asc_msg_in: msg %x %x %x\n",
142652889Sbostic 				state->msg_in[0],
142752889Sbostic 				state->msg_in[1],
142852889Sbostic 				state->msg_in[2]);
142952889Sbostic #endif
143052889Sbostic 		switch (state->msg_in[0]) {
143152889Sbostic 		case SCSI_SYNCHRONOUS_XFER:
143252889Sbostic 			state->flags |= DID_SYNC;
143352889Sbostic 			state->sync_offset = state->msg_in[2];
143452889Sbostic 
143552889Sbostic 			/* convert SCSI period to ASC period */
143652889Sbostic 			i = state->msg_in[1] / 10;
143752889Sbostic 			if (i < ASC_MIN_PERIOD)
143852889Sbostic 				i = ASC_MIN_PERIOD;
143952889Sbostic 			else if (i >= ASC_MAX_PERIOD) {
144052889Sbostic 				/* can't do sync transfer, period too long */
144152889Sbostic 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
144252889Sbostic 					asc - asc_softc, asc->target, i);
144352889Sbostic 				i = ASC_MAX_PERIOD;
144452889Sbostic 				state->sync_offset = 0;
144552889Sbostic 			}
144652889Sbostic 			if ((i * 10) != state->msg_in[1])
144752889Sbostic 				i++;
144852889Sbostic 			state->sync_period = i & 0x1F;
144952889Sbostic 
145052889Sbostic 			/*
145152889Sbostic 			 * If this is a request, check minimums and
145252889Sbostic 			 * send back an acknowledge.
145352889Sbostic 			 */
145452889Sbostic 			if (!(state->flags & TRY_SYNC)) {
145552889Sbostic 				regs->asc_cmd = ASC_CMD_SET_ATN;
145652889Sbostic 				MachEmptyWriteBuffer();
145752889Sbostic 
145852889Sbostic 				if (state->sync_period < ASC_MIN_PERIOD)
145952889Sbostic 					state->sync_period =
146052889Sbostic 						ASC_MIN_PERIOD;
146152889Sbostic 				if (state->sync_offset > ASC_MAX_OFFSET)
146252889Sbostic 					state->sync_offset =
146352889Sbostic 						ASC_MAX_OFFSET;
146452889Sbostic 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
146552889Sbostic 				regs->asc_syn_p = state->sync_period;
146652889Sbostic 				regs->asc_syn_o = state->sync_offset;
146752889Sbostic 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
146852889Sbostic 				return (0);
146952889Sbostic 			}
147052889Sbostic 
147152889Sbostic 			regs->asc_syn_p = state->sync_period;
147252889Sbostic 			regs->asc_syn_o = state->sync_offset;
147352889Sbostic 			goto done;
147452889Sbostic 
147552889Sbostic 		default:
147652889Sbostic 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
147752889Sbostic 				asc - asc_softc, asc->target,
147852889Sbostic 				state->msg_in[0]);
147952889Sbostic 			goto reject;
148052889Sbostic 		}
148152889Sbostic 	}
148252889Sbostic 
148352889Sbostic 	/* process first byte of a message */
148452889Sbostic #ifdef DEBUG
148552889Sbostic 	if (asc_debug > 2)
1486*52942Sralph 		printf("asc_msg_in: msg %x\n", msg);
148752889Sbostic #endif
148852889Sbostic 	switch (msg) {
148952889Sbostic #if 0
149052889Sbostic 	case SCSI_MESSAGE_REJECT:
149152889Sbostic 		printf(" did not like SYNCH xfer "); /* XXX */
149252889Sbostic 		state->flags |= DID_SYNC;
149352889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
149452889Sbostic 		status = asc_wait(regs, ASC_CSR_INT);
149552889Sbostic 		ir = regs->asc_intr;
149652889Sbostic 		/* some just break out here, some dont */
149752889Sbostic 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
149852889Sbostic 			regs->asc_fifo = SCSI_ABORT;
149952889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
150052889Sbostic 			status = asc_wait(regs, ASC_CSR_INT);
150152889Sbostic 			ir = regs->asc_intr;
150252889Sbostic 		}
150352889Sbostic 		if (ir & ASC_INT_DISC) {
150452889Sbostic 			asc_end(asc, status, 0, ir);
150552889Sbostic 			return (0);
150652889Sbostic 		}
150752889Sbostic 		goto status;
150852889Sbostic #endif
150952889Sbostic 
151052889Sbostic 	case SCSI_EXTENDED_MSG: /* read an extended message */
151152889Sbostic 		/* setup to read message length next */
151252889Sbostic 		state->msglen = -1;
151352889Sbostic 		state->msgcnt = 0;
151452889Sbostic 		return (1);
151552889Sbostic 
151652889Sbostic 	case SCSI_NO_OP:
151752889Sbostic 		break;
151852889Sbostic 
151952889Sbostic 	case SCSI_SAVE_DATA_POINTER:
152052889Sbostic 		/* expect another message */
152152889Sbostic 		return (1);
152252889Sbostic 
152352889Sbostic 	case SCSI_RESTORE_POINTERS:
152452889Sbostic 		/*
152552889Sbostic 		 * Need to do the following if resuming synchonous data in
152652889Sbostic 		 * on an odd byte boundary.
152752889Sbostic 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
152852889Sbostic 		 */
152952889Sbostic 		break;
153052889Sbostic 
153152889Sbostic 	case SCSI_DISCONNECT:
153252889Sbostic 		if (state->flags & DISCONN)
153352889Sbostic 			goto abort;
153452889Sbostic 		state->flags |= DISCONN;
1535*52942Sralph 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1536*52942Sralph 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1537*52942Sralph 		return (0);
153852889Sbostic 
153952889Sbostic 	default:
154052889Sbostic 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
154152889Sbostic 			asc - asc_softc, asc->target, msg);
154252889Sbostic 	reject:
154352889Sbostic 		/* request a message out before acknowledging this message */
154452889Sbostic 		state->msg_out = SCSI_MESSAGE_REJECT;
154552889Sbostic 		regs->asc_cmd = ASC_CMD_SET_ATN;
154652889Sbostic 		MachEmptyWriteBuffer();
154752889Sbostic 	}
154852889Sbostic 
154952889Sbostic done:
155052889Sbostic 	/* return to original script */
155152889Sbostic 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
155252889Sbostic 	if (!state->script) {
155352889Sbostic 	abort:
155452889Sbostic #ifdef DEBUG
1555*52942Sralph 		asc_DumpLog("asc_msg_in");
155652889Sbostic #endif
1557*52942Sralph 		panic("asc_msg_in");
155852889Sbostic 	}
155952889Sbostic 	asc->script = state->script;
156052889Sbostic 	state->script = (script_t *)0;
156152889Sbostic 	return (0);
156252889Sbostic }
156352889Sbostic 
1564*52942Sralph /* ARGSUSED */
1565*52942Sralph static int
1566*52942Sralph asc_disconnect(asc, status, ss, ir)
1567*52942Sralph 	register asc_softc_t asc;
1568*52942Sralph 	register int status, ss, ir;
1569*52942Sralph {
1570*52942Sralph 	register State *state = &asc->st[asc->target];
1571*52942Sralph 
1572*52942Sralph 	asc->target = -1;
1573*52942Sralph 	asc->state = ASC_STATE_RESEL;
1574*52942Sralph 	return (1);
1575*52942Sralph }
1576*52942Sralph 
157752889Sbostic #ifdef DEBUG
157852889Sbostic asc_DumpLog(str)
157952889Sbostic 	char *str;
158052889Sbostic {
158152889Sbostic 	register struct asc_log *lp;
158252889Sbostic 	register u_int status;
158352889Sbostic 
158452889Sbostic 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
158552889Sbostic 		asc_debug_bn, asc_debug_sz);
158652889Sbostic 	lp = asc_logp + 1;
158752889Sbostic 	if (lp > &asc_log[NLOG])
158852889Sbostic 		lp = asc_log;
158952889Sbostic 	while (lp != asc_logp) {
159052889Sbostic 		status = lp->status;
159152889Sbostic 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
159252889Sbostic 			status >> 24,
159352889Sbostic 			lp->target,
159452889Sbostic 			(status >> 16) & 0xFF,
159552889Sbostic 			(status >> 8) & 0xFF,
159652889Sbostic 			status & 0XFF,
159752889Sbostic 			lp->state,
159852889Sbostic 			asc_scripts[lp->state].condition,
159952889Sbostic 			lp->msg);
160052889Sbostic 		if (++lp >= &asc_log[NLOG])
160152889Sbostic 			lp = asc_log;
160252889Sbostic 	}
160352889Sbostic }
160452889Sbostic #endif
160552889Sbostic 
160652889Sbostic #endif	/* NASC > 0 */
1607