xref: /csrg-svn/sys/pmax/dev/asc.c (revision 52889)
1*52889Sbostic /*-
2*52889Sbostic  * Copyright (c) 1992 The Regents of the University of California.
3*52889Sbostic  * All rights reserved.
4*52889Sbostic  *
5*52889Sbostic  * This code is derived from software contributed to Berkeley by
6*52889Sbostic  * Ralph Campbell.
7*52889Sbostic  *
8*52889Sbostic  * %sccs.include.redist.c%
9*52889Sbostic  *
10*52889Sbostic  *	@(#)asc.c	7.1 (Berkeley) 03/09/92
11*52889Sbostic  */
12*52889Sbostic 
13*52889Sbostic /*
14*52889Sbostic  * Mach Operating System
15*52889Sbostic  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
16*52889Sbostic  * All Rights Reserved.
17*52889Sbostic  *
18*52889Sbostic  * Permission to use, copy, modify and distribute this software and its
19*52889Sbostic  * documentation is hereby granted, provided that both the copyright
20*52889Sbostic  * notice and this permission notice appear in all copies of the
21*52889Sbostic  * software, derivative works or modified versions, and any portions
22*52889Sbostic  * thereof, and that both notices appear in supporting documentation.
23*52889Sbostic  *
24*52889Sbostic  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
25*52889Sbostic  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26*52889Sbostic  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27*52889Sbostic  *
28*52889Sbostic  * Carnegie Mellon requests users of this software to return to
29*52889Sbostic  *
30*52889Sbostic  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31*52889Sbostic  *  School of Computer Science
32*52889Sbostic  *  Carnegie Mellon University
33*52889Sbostic  *  Pittsburgh PA 15213-3890
34*52889Sbostic  *
35*52889Sbostic  * any improvements or extensions that they make and grant Carnegie the
36*52889Sbostic  * rights to redistribute these changes.
37*52889Sbostic  */
38*52889Sbostic 
39*52889Sbostic /*
40*52889Sbostic  * HISTORY
41*52889Sbostic  * $Log:	scsi_53C94_hdw.c,v $
42*52889Sbostic  * Revision 2.5  91/02/05  17:45:07  mrt
43*52889Sbostic  * 	Added author notices
44*52889Sbostic  * 	[91/02/04  11:18:43  mrt]
45*52889Sbostic  *
46*52889Sbostic  * 	Changed to use new Mach copyright
47*52889Sbostic  * 	[91/02/02  12:17:20  mrt]
48*52889Sbostic  *
49*52889Sbostic  * Revision 2.4  91/01/08  15:48:24  rpd
50*52889Sbostic  * 	Added continuation argument to thread_block.
51*52889Sbostic  * 	[90/12/27            rpd]
52*52889Sbostic  *
53*52889Sbostic  * Revision 2.3  90/12/05  23:34:48  af
54*52889Sbostic  * 	Recovered from pmax merge.. and from the destruction of a disk.
55*52889Sbostic  * 	[90/12/03  23:40:40  af]
56*52889Sbostic  *
57*52889Sbostic  * Revision 2.1.1.1  90/11/01  03:39:09  af
58*52889Sbostic  * 	Created, from the DEC specs:
59*52889Sbostic  * 	"PMAZ-AA TURBOchannel SCSI Module Functional Specification"
60*52889Sbostic  * 	Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
61*52889Sbostic  * 	And from the NCR data sheets
62*52889Sbostic  * 	"NCR 53C94, 53C95, 53C96 Advances SCSI Controller"
63*52889Sbostic  * 	[90/09/03            af]
64*52889Sbostic  */
65*52889Sbostic 
66*52889Sbostic /*
67*52889Sbostic  *	File: scsi_53C94_hdw.h
68*52889Sbostic  * 	Author: Alessandro Forin, Carnegie Mellon University
69*52889Sbostic  *	Date:	9/90
70*52889Sbostic  *
71*52889Sbostic  *	Bottom layer of the SCSI driver: chip-dependent functions
72*52889Sbostic  *
73*52889Sbostic  *	This file contains the code that is specific to the NCR 53C94
74*52889Sbostic  *	SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
75*52889Sbostic  *	operation, and interrupt routine.
76*52889Sbostic  */
77*52889Sbostic 
78*52889Sbostic /*
79*52889Sbostic  * This layer works based on small simple 'scripts' that are installed
80*52889Sbostic  * at the start of the command and drive the chip to completion.
81*52889Sbostic  * The idea comes from the specs of the NCR 53C700 'script' processor.
82*52889Sbostic  *
83*52889Sbostic  * There are various reasons for this, mainly
84*52889Sbostic  * - Performance: identify the common (successful) path, and follow it;
85*52889Sbostic  *   at interrupt time no code is needed to find the current status
86*52889Sbostic  * - Code size: it should be easy to compact common operations
87*52889Sbostic  * - Adaptability: the code skeleton should adapt to different chips without
88*52889Sbostic  *   terrible complications.
89*52889Sbostic  * - Error handling: and it is easy to modify the actions performed
90*52889Sbostic  *   by the scripts to cope with strange but well identified sequences
91*52889Sbostic  *
92*52889Sbostic  */
93*52889Sbostic 
94*52889Sbostic #include "asc.h"
95*52889Sbostic #if NASC > 0
96*52889Sbostic 
97*52889Sbostic #include "param.h"
98*52889Sbostic #include "systm.h"
99*52889Sbostic #include "dkstat.h"
100*52889Sbostic #include "buf.h"
101*52889Sbostic #include "conf.h"
102*52889Sbostic #include "errno.h"
103*52889Sbostic 
104*52889Sbostic #include "device.h"
105*52889Sbostic #include "scsi.h"
106*52889Sbostic #include "ascreg.h"
107*52889Sbostic 
108*52889Sbostic #define ASC_OFFSET_53C94	0x0		/* from module base */
109*52889Sbostic #define ASC_OFFSET_DMAR		0x40000		/* DMA Address Register */
110*52889Sbostic #define ASC_OFFSET_RAM		0x80000		/* SRAM Buffer */
111*52889Sbostic #define ASC_OFFSET_ROM		0xc0000		/* Diagnostic ROM */
112*52889Sbostic 
113*52889Sbostic #define	ASC_RAM_SIZE		0x20000		/* 128k (32k*32) */
114*52889Sbostic 
115*52889Sbostic /*
116*52889Sbostic  * DMA Address Register
117*52889Sbostic  */
118*52889Sbostic #define ASC_DMAR_MASK		0x1ffff		/* 17 bits, 128k */
119*52889Sbostic #define ASC_DMAR_WRITE		0x80000000	/* DMA direction bit */
120*52889Sbostic #define	ASC_DMA_ADDR(x)		((unsigned)(x)) & ASC_DMAR_MASK
121*52889Sbostic 
122*52889Sbostic /*
123*52889Sbostic  * Synch xfer parameters, and timing conversions
124*52889Sbostic  */
125*52889Sbostic #define SCSI_MIN_PERIOD	50	/* in 4 nsecs units */
126*52889Sbostic #define ASC_MIN_PERIOD	5	/* in CLKS/BYTE, 1 CLK = 40nsecs */
127*52889Sbostic #define ASC_MAX_PERIOD	35	/* in CLKS/BYTE, 1 CLK = 40nsecs */
128*52889Sbostic #define ASC_MAX_OFFSET	15	/* pure number */
129*52889Sbostic 
130*52889Sbostic int	asc_to_scsi_period[] = {
131*52889Sbostic 	320,
132*52889Sbostic 	330,
133*52889Sbostic 	340,
134*52889Sbostic 	350,
135*52889Sbostic 	50,
136*52889Sbostic 	50,
137*52889Sbostic 	60,
138*52889Sbostic 	70,
139*52889Sbostic 	80,
140*52889Sbostic 	90,
141*52889Sbostic 	100,
142*52889Sbostic 	110,
143*52889Sbostic 	120,
144*52889Sbostic 	130,
145*52889Sbostic 	140,
146*52889Sbostic 	150,
147*52889Sbostic 	160,
148*52889Sbostic 	170,
149*52889Sbostic 	180,
150*52889Sbostic 	190,
151*52889Sbostic 	200,
152*52889Sbostic 	210,
153*52889Sbostic 	220,
154*52889Sbostic 	230,
155*52889Sbostic 	240,
156*52889Sbostic 	250,
157*52889Sbostic 	260,
158*52889Sbostic 	270,
159*52889Sbostic 	280,
160*52889Sbostic 	290,
161*52889Sbostic 	300,
162*52889Sbostic 	310,
163*52889Sbostic };
164*52889Sbostic 
165*52889Sbostic /*
166*52889Sbostic  * Internal forward declarations.
167*52889Sbostic  */
168*52889Sbostic static void asc_reset();
169*52889Sbostic static void asc_startcmd();
170*52889Sbostic 
171*52889Sbostic #ifdef DEBUG
172*52889Sbostic int	asc_debug = 1;
173*52889Sbostic int	asc_debug_cmd;
174*52889Sbostic int	asc_debug_bn;
175*52889Sbostic int	asc_debug_sz;
176*52889Sbostic #define NLOG 16
177*52889Sbostic struct asc_log {
178*52889Sbostic 	u_int	status;
179*52889Sbostic 	u_char	state;
180*52889Sbostic 	u_char	msg;
181*52889Sbostic 	int	target;
182*52889Sbostic } asc_log[NLOG], *asc_logp = asc_log;
183*52889Sbostic #define PACK(unit, status, ss, ir) \
184*52889Sbostic 	((unit << 24) | (status << 16) | (ss << 8) | ir)
185*52889Sbostic #endif
186*52889Sbostic 
187*52889Sbostic /*
188*52889Sbostic  * Scripts are entries in a state machine table.
189*52889Sbostic  * A script has four parts: a pre-condition, an action, a command to the chip,
190*52889Sbostic  * and an index into asc_scripts for the next state. The first triggers error
191*52889Sbostic  * handling if not satisfied and in our case it is formed by the
192*52889Sbostic  * values of the interrupt register and status register, this
193*52889Sbostic  * basically captures the phase of the bus and the TC and BS
194*52889Sbostic  * bits.  The action part is just a function pointer, and the
195*52889Sbostic  * command is what the 53C94 should be told to do at the end
196*52889Sbostic  * of the action processing.  This command is only issued and the
197*52889Sbostic  * script proceeds if the action routine returns TRUE.
198*52889Sbostic  * See asc_intr() for how and where this is all done.
199*52889Sbostic  */
200*52889Sbostic typedef struct script {
201*52889Sbostic 	int		condition;	/* expected state at interrupt time */
202*52889Sbostic 	int		(*action)();	/* extra operations */
203*52889Sbostic 	int		command;	/* command to the chip */
204*52889Sbostic 	struct script	*next;		/* index into asc_scripts for next state */
205*52889Sbostic } script_t;
206*52889Sbostic 
207*52889Sbostic /* Matching on the condition value */
208*52889Sbostic #define	SCRIPT_MATCH(ir, csr)		((ir) | (ASC_PHASE(csr) << 8))
209*52889Sbostic 
210*52889Sbostic /* forward decls of script actions */
211*52889Sbostic int	script_nop();			/* when nothing needed */
212*52889Sbostic int	asc_end();			/* all come to an end */
213*52889Sbostic int	asc_get_status();		/* get status from target */
214*52889Sbostic int	asc_dma_in();			/* start reading data from target */
215*52889Sbostic int	asc_last_dma_in();		/* cleanup after all data is read */
216*52889Sbostic int	asc_resume_dma_in();		/* resume DMA after a disconnect */
217*52889Sbostic int	asc_dma_out();			/* send data to target via dma */
218*52889Sbostic int	asc_last_dma_out();		/* cleanup after all data is written */
219*52889Sbostic int	asc_resume_dma_out();		/* resume DMA after a disconnect */
220*52889Sbostic int	asc_sendsync();			/* negotiate sync xfer */
221*52889Sbostic int	asc_replysync();		/* negotiate sync xfer */
222*52889Sbostic int	asc_recvmsg();			/* process a message byte */
223*52889Sbostic 
224*52889Sbostic /* Define the index into asc_scripts for various state transitions */
225*52889Sbostic #define	SCRIPT_DATA_IN		0
226*52889Sbostic #define	SCRIPT_DATA_OUT		2
227*52889Sbostic #define	SCRIPT_SIMPLE		4
228*52889Sbostic #define	SCRIPT_GET_STATUS	5
229*52889Sbostic #define	SCRIPT_MSG_IN		7
230*52889Sbostic #define	SCRIPT_REPLY_SYNC	9
231*52889Sbostic #define	SCRIPT_RESUME_IN	10
232*52889Sbostic #define	SCRIPT_RESUME_OUT	11
233*52889Sbostic #define	SCRIPT_TRY_SYNC		12
234*52889Sbostic #define	SCRIPT_RESEL		15
235*52889Sbostic #define	SCRIPT_RESUME_DMA_IN	16
236*52889Sbostic #define	SCRIPT_RESUME_DMA_OUT	17
237*52889Sbostic 
238*52889Sbostic /*
239*52889Sbostic  * Scripts
240*52889Sbostic  */
241*52889Sbostic script_t asc_scripts[] = {
242*52889Sbostic 	/* data in */
243*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
244*52889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
245*52889Sbostic 		&asc_scripts[SCRIPT_DATA_IN + 1] },
246*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
247*52889Sbostic 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
248*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
249*52889Sbostic 
250*52889Sbostic 	/* data out */
251*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  2 */
252*52889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
253*52889Sbostic 		&asc_scripts[SCRIPT_DATA_OUT + 1] },
254*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  3 */
255*52889Sbostic 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
256*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
257*52889Sbostic 
258*52889Sbostic 	/* simple command with no data transfer */
259*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  4 */
260*52889Sbostic 		script_nop, ASC_CMD_I_COMPLETE,
261*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
262*52889Sbostic 
263*52889Sbostic 	/* get status and finish command */
264*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  5 */
265*52889Sbostic 		asc_get_status, ASC_CMD_MSG_ACPT,
266*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS + 1] },
267*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  6 */
268*52889Sbostic 		asc_end, ASC_CMD_NOP,
269*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS + 1] },
270*52889Sbostic 
271*52889Sbostic 	/* message in */
272*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
273*52889Sbostic 		asc_recvmsg, ASC_CMD_MSG_ACPT,
274*52889Sbostic 		&asc_scripts[SCRIPT_MSG_IN + 1] },
275*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/*  8 */
276*52889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
277*52889Sbostic 		&asc_scripts[SCRIPT_MSG_IN] },
278*52889Sbostic 
279*52889Sbostic 	/* send synchonous negotiation reply */
280*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/*  9 */
281*52889Sbostic 		asc_replysync, ASC_CMD_XFER_INFO,
282*52889Sbostic 		&asc_scripts[SCRIPT_REPLY_SYNC] },
283*52889Sbostic 
284*52889Sbostic 	/* resume data in after a message */
285*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 10 */
286*52889Sbostic 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
287*52889Sbostic 		&asc_scripts[SCRIPT_DATA_IN + 1] },
288*52889Sbostic 
289*52889Sbostic 	/* resume data out after a message */
290*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 11 */
291*52889Sbostic 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
292*52889Sbostic 		&asc_scripts[SCRIPT_DATA_OUT + 1] },
293*52889Sbostic 
294*52889Sbostic 	/* try to negotiate synchonous transfer parameters */
295*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
296*52889Sbostic 		asc_sendsync, ASC_CMD_XFER_INFO,
297*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
298*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 13 */
299*52889Sbostic 		script_nop, ASC_CMD_XFER_INFO,
300*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
301*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 14 */
302*52889Sbostic 		asc_recvmsg, ASC_CMD_MSG_ACPT,
303*52889Sbostic 		&asc_scripts[SCRIPT_GET_STATUS] },
304*52889Sbostic 
305*52889Sbostic 	/* reselect sequence: this is just a placeholder so match fails */
306*52889Sbostic 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 15 */
307*52889Sbostic 		script_nop, ASC_CMD_MSG_ACPT,
308*52889Sbostic 		&asc_scripts[SCRIPT_RESEL] },
309*52889Sbostic 
310*52889Sbostic 	/* resume data in after a disconnect */
311*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 16 */
312*52889Sbostic 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
313*52889Sbostic 		&asc_scripts[SCRIPT_DATA_IN + 1] },
314*52889Sbostic 
315*52889Sbostic 	/* resume data out after a disconnect */
316*52889Sbostic 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 17 */
317*52889Sbostic 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
318*52889Sbostic 		&asc_scripts[SCRIPT_DATA_OUT + 1] },
319*52889Sbostic };
320*52889Sbostic 
321*52889Sbostic /*
322*52889Sbostic  * State kept for each active SCSI device.
323*52889Sbostic  */
324*52889Sbostic typedef struct scsi_state {
325*52889Sbostic 	script_t *script;	/* saved script while processing error */
326*52889Sbostic 	int	statusByte;	/* status byte returned during STATUS_PHASE */
327*52889Sbostic 	int	error;		/* errno to pass back to device driver */
328*52889Sbostic 	u_char	*dmaBufAddr;	/* DMA buffer address */
329*52889Sbostic 	u_int	dmaBufSize;	/* DMA buffer size */
330*52889Sbostic 	int	dmalen;		/* amount to transfer in this chunk */
331*52889Sbostic 	int	dmaresid;	/* amount not transfered if chunk suspended */
332*52889Sbostic 	int	buflen;		/* total remaining amount of data to transfer */
333*52889Sbostic 	char	*buf;		/* current pointer within scsicmd->buf */
334*52889Sbostic 	int	flags;		/* see below */
335*52889Sbostic 	int	msglen;		/* number of message bytes to read */
336*52889Sbostic 	int	msgcnt;		/* number of message bytes received */
337*52889Sbostic 	u_char	sync_period;	/* DMA synchronous period */
338*52889Sbostic 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
339*52889Sbostic 	u_char	msg_out;	/* next MSG_OUT byte to send */
340*52889Sbostic 	u_char	msg_in[16];	/* buffer for multibyte messages */
341*52889Sbostic } State;
342*52889Sbostic 
343*52889Sbostic /* state flags */
344*52889Sbostic #define DISCONN		0x01	/* true if currently disconnected from bus */
345*52889Sbostic #define FIRST_DMA	0x02	/* true if no data DMA started yet */
346*52889Sbostic #define DMA_IN		0x04	/* true if reading from SCSI device */
347*52889Sbostic #define DMA_OUT		0x10	/* true if writing to SCSI device */
348*52889Sbostic #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
349*52889Sbostic #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
350*52889Sbostic 
351*52889Sbostic #define ASC_NCMD	7
352*52889Sbostic /*
353*52889Sbostic  * State kept for each active SCSI host interface (53C94).
354*52889Sbostic  */
355*52889Sbostic struct asc_softc {
356*52889Sbostic 	asc_regmap_t	*regs;		/* chip address */
357*52889Sbostic 	volatile int	*dmar;		/* DMA address register address */
358*52889Sbostic 	volatile u_char	*buff;		/* RAM buffer address */
359*52889Sbostic 	int		myid;		/* SCSI ID of this interface */
360*52889Sbostic 	int		myidmask;	/* ~(1 << myid) */
361*52889Sbostic 	int		state;		/* current SCSI connection state */
362*52889Sbostic 	int		target;		/* target SCSI ID if busy */
363*52889Sbostic 	script_t	*script;	/* next expected interrupt & action */
364*52889Sbostic 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
365*52889Sbostic 	State		st[ASC_NCMD];	/* state info for each active command */
366*52889Sbostic } asc_softc[NASC];
367*52889Sbostic 
368*52889Sbostic #define	ASC_STATE_IDLE		0	/* idle state */
369*52889Sbostic #define	ASC_STATE_BUSY		1	/* selecting or currently connected */
370*52889Sbostic #define ASC_STATE_TARGET	2	/* currently selected as target */
371*52889Sbostic #define ASC_STATE_RESEL		3	/* currently waiting for reselect */
372*52889Sbostic 
373*52889Sbostic typedef struct asc_softc *asc_softc_t;
374*52889Sbostic 
375*52889Sbostic /*
376*52889Sbostic  * Definition of the controller for the auto-configuration program.
377*52889Sbostic  */
378*52889Sbostic int	asc_probe();
379*52889Sbostic void	asc_start();
380*52889Sbostic void	asc_intr();
381*52889Sbostic struct	driver ascdriver = {
382*52889Sbostic 	"asc", asc_probe, asc_start, 0, asc_intr,
383*52889Sbostic };
384*52889Sbostic 
385*52889Sbostic /*
386*52889Sbostic  * Test to see if device is present.
387*52889Sbostic  * Return true if found and initialized ok.
388*52889Sbostic  */
389*52889Sbostic asc_probe(cp)
390*52889Sbostic 	register struct pmax_ctlr *cp;
391*52889Sbostic {
392*52889Sbostic 	register asc_softc_t asc;
393*52889Sbostic 	register asc_regmap_t *regs;
394*52889Sbostic 	int unit, id, s, i;
395*52889Sbostic 
396*52889Sbostic 	if ((unit = cp->pmax_unit) >= NASC)
397*52889Sbostic 		return (0);
398*52889Sbostic 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
399*52889Sbostic 		return (0);
400*52889Sbostic 	asc = &asc_softc[unit];
401*52889Sbostic 
402*52889Sbostic 	/*
403*52889Sbostic 	 * Initialize hw descriptor, cache some pointers
404*52889Sbostic 	 */
405*52889Sbostic 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
406*52889Sbostic 	asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
407*52889Sbostic 	asc->buff = (volatile u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
408*52889Sbostic 
409*52889Sbostic 	asc->state = ASC_STATE_IDLE;
410*52889Sbostic 	asc->target = -1;
411*52889Sbostic 
412*52889Sbostic 	regs = asc->regs;
413*52889Sbostic 
414*52889Sbostic 	/*
415*52889Sbostic 	 * Reset chip, fully.  Note that interrupts are already enabled.
416*52889Sbostic 	 */
417*52889Sbostic 	s = splbio();
418*52889Sbostic 
419*52889Sbostic 	/* preserve our ID for now */
420*52889Sbostic 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
421*52889Sbostic 	asc->myidmask = ~(1 << asc->myid);
422*52889Sbostic 
423*52889Sbostic 	asc_reset(asc, regs);
424*52889Sbostic 
425*52889Sbostic 	/*
426*52889Sbostic 	 * Our SCSI id on the bus.
427*52889Sbostic 	 * The user can set this via the prom on 3maxen/pmaxen.
428*52889Sbostic 	 * If this changes it is easy to fix: make a default that
429*52889Sbostic 	 * can be changed as boot arg.
430*52889Sbostic 	 */
431*52889Sbostic #ifdef	unneeded
432*52889Sbostic 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
433*52889Sbostic 			      (scsi_initiator_id[unit] & 0x7);
434*52889Sbostic #endif
435*52889Sbostic 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
436*52889Sbostic 	splx(s);
437*52889Sbostic 
438*52889Sbostic 	/*
439*52889Sbostic 	 * Statically partition the DMA buffer between targets.
440*52889Sbostic 	 * This way we will eventually be able to attach/detach
441*52889Sbostic 	 * drives on-fly.  And 18k/target is plenty for normal use.
442*52889Sbostic 	 */
443*52889Sbostic #define PER_TGT_DMA_SIZE	((ASC_RAM_SIZE/7) & ~(sizeof(int)-1))
444*52889Sbostic 
445*52889Sbostic 	/*
446*52889Sbostic 	 * Give each target its own DMA buffer region.
447*52889Sbostic 	 * We may want to try ping ponging buffers later.
448*52889Sbostic 	 */
449*52889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
450*52889Sbostic 		asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i;
451*52889Sbostic 		asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE;
452*52889Sbostic 	}
453*52889Sbostic 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
454*52889Sbostic 		unit, cp->pmax_addr, cp->pmax_pri, id);
455*52889Sbostic 	return (1);
456*52889Sbostic }
457*52889Sbostic 
458*52889Sbostic /*
459*52889Sbostic  * Start activity on a SCSI device.
460*52889Sbostic  * We maintain information on each device separately since devices can
461*52889Sbostic  * connect/disconnect during an operation.
462*52889Sbostic  */
463*52889Sbostic void
464*52889Sbostic asc_start(scsicmd)
465*52889Sbostic 	register ScsiCmd *scsicmd;	/* command to start */
466*52889Sbostic {
467*52889Sbostic 	register struct scsi_device *sdp = scsicmd->sd;
468*52889Sbostic 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
469*52889Sbostic 	int s;
470*52889Sbostic 
471*52889Sbostic 	s = splbio();
472*52889Sbostic 	/*
473*52889Sbostic 	 * Check if another command is already in progress.
474*52889Sbostic 	 * We may have to change this if we allow SCSI devices with
475*52889Sbostic 	 * separate LUNs.
476*52889Sbostic 	 */
477*52889Sbostic 	if (asc->cmd[sdp->sd_drive]) {
478*52889Sbostic 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
479*52889Sbostic 			sdp->sd_driver->d_name);
480*52889Sbostic 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
481*52889Sbostic 			scsicmd->buflen, 0);
482*52889Sbostic 		splx(s);
483*52889Sbostic 	}
484*52889Sbostic 	asc->cmd[sdp->sd_drive] = scsicmd;
485*52889Sbostic 	asc_startcmd(asc, sdp->sd_drive);
486*52889Sbostic 	splx(s);
487*52889Sbostic }
488*52889Sbostic 
489*52889Sbostic static void
490*52889Sbostic asc_reset(asc, regs)
491*52889Sbostic 	asc_softc_t asc;
492*52889Sbostic 	asc_regmap_t *regs;
493*52889Sbostic {
494*52889Sbostic 
495*52889Sbostic 	/*
496*52889Sbostic 	 * Reset chip and wait till done
497*52889Sbostic 	 */
498*52889Sbostic 	regs->asc_cmd = ASC_CMD_RESET;
499*52889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
500*52889Sbostic 
501*52889Sbostic 	/* spec says this is needed after reset */
502*52889Sbostic 	regs->asc_cmd = ASC_CMD_NOP;
503*52889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
504*52889Sbostic 
505*52889Sbostic 	/*
506*52889Sbostic 	 * Set up various chip parameters
507*52889Sbostic 	 */
508*52889Sbostic 	regs->asc_ccf = ASC_CCF_25MHz;	/* 25 MHz clock */
509*52889Sbostic 	MachEmptyWriteBuffer(); DELAY(25);
510*52889Sbostic 	regs->asc_sel_timo = ASC_TIMEOUT_250;
511*52889Sbostic 	/* restore our ID */
512*52889Sbostic 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
513*52889Sbostic 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_EPL;
514*52889Sbostic 	regs->asc_cnfg3 = 0;
515*52889Sbostic 	/* zero anything else */
516*52889Sbostic 	ASC_TC_PUT(regs, 0);
517*52889Sbostic 	regs->asc_sel_timo = ASC_TIMEOUT_250;
518*52889Sbostic 	regs->asc_syn_p = ASC_MIN_PERIOD;
519*52889Sbostic 	regs->asc_syn_o = 0;	/* async for now */
520*52889Sbostic 	MachEmptyWriteBuffer();
521*52889Sbostic }
522*52889Sbostic 
523*52889Sbostic /*
524*52889Sbostic  * Start a SCSI command on a target.
525*52889Sbostic  */
526*52889Sbostic static void
527*52889Sbostic asc_startcmd(asc, target)
528*52889Sbostic 	asc_softc_t asc;
529*52889Sbostic 	int target;
530*52889Sbostic {
531*52889Sbostic 	register asc_regmap_t *regs;
532*52889Sbostic 	register ScsiCmd *scsicmd;
533*52889Sbostic 	register State *state;
534*52889Sbostic 	int len;
535*52889Sbostic 
536*52889Sbostic 	/*
537*52889Sbostic 	 * See if another target is currently selected on this SCSI bus.
538*52889Sbostic 	 */
539*52889Sbostic 	if (asc->target >= 0)
540*52889Sbostic 		return;
541*52889Sbostic 
542*52889Sbostic 	regs = asc->regs;
543*52889Sbostic 
544*52889Sbostic 	/*
545*52889Sbostic 	 * Check to see if a reselection is in progress and if so,
546*52889Sbostic 	 * try to cancel it or respond to the reselection if it won.
547*52889Sbostic 	 */
548*52889Sbostic 	if (asc->state == ASC_STATE_RESEL) {
549*52889Sbostic 		regs->asc_cmd = ASC_CMD_DISABLE_SEL;
550*52889Sbostic 		while (!(regs->asc_status & ASC_CSR_INT))
551*52889Sbostic 			DELAY(1);
552*52889Sbostic 		asc_intr(asc - asc_softc);
553*52889Sbostic 		/* we will be busy if a reselecting device won */
554*52889Sbostic 		if (asc->state == ASC_STATE_BUSY)
555*52889Sbostic 			return;
556*52889Sbostic 	}
557*52889Sbostic 
558*52889Sbostic 	asc->state = ASC_STATE_BUSY;
559*52889Sbostic 	asc->target = target;
560*52889Sbostic 
561*52889Sbostic 	/* cache some pointers */
562*52889Sbostic 	scsicmd = asc->cmd[target];
563*52889Sbostic 	state = &asc->st[target];
564*52889Sbostic 
565*52889Sbostic #ifdef DEBUG
566*52889Sbostic 	if (asc_debug > 1) {
567*52889Sbostic 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
568*52889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
569*52889Sbostic 			scsicmd->cmd[0], scsicmd->buflen);
570*52889Sbostic 	}
571*52889Sbostic 	asc_debug_cmd = scsicmd->cmd[0];
572*52889Sbostic 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
573*52889Sbostic 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
574*52889Sbostic 			(scsicmd->cmd[3] << 16) |
575*52889Sbostic 			(scsicmd->cmd[4] << 8) |
576*52889Sbostic 			scsicmd->cmd[5];
577*52889Sbostic 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
578*52889Sbostic 	}
579*52889Sbostic 	asc_logp->status = PACK(asc - asc_softc, 0, 0, 0);
580*52889Sbostic 	asc_logp->target = asc->target;
581*52889Sbostic 	asc_logp->state = 0;
582*52889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
583*52889Sbostic 		asc_logp = asc_log;
584*52889Sbostic #endif
585*52889Sbostic 
586*52889Sbostic 	/*
587*52889Sbostic 	 * Init the chip and target state.
588*52889Sbostic 	 */
589*52889Sbostic 	regs->asc_cmd = ASC_CMD_FLUSH;
590*52889Sbostic 	state->flags = FIRST_DMA | (state->flags & DID_SYNC);
591*52889Sbostic 	state->error = 0;
592*52889Sbostic 	state->script = (script_t *)0;
593*52889Sbostic 	state->msg_out = SCSI_NO_OP;
594*52889Sbostic 
595*52889Sbostic 	/*
596*52889Sbostic 	 * Copy command data to the DMA buffer.
597*52889Sbostic 	 */
598*52889Sbostic 	len = scsicmd->cmdlen;
599*52889Sbostic 	state->dmalen = len;
600*52889Sbostic 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
601*52889Sbostic 
602*52889Sbostic 	/* check for simple SCSI command with no data transfer */
603*52889Sbostic 	if ((state->buflen = scsicmd->buflen) == 0) {
604*52889Sbostic 		/* check for sync negotiation */
605*52889Sbostic 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
606*52889Sbostic 		    !(state->flags & DID_SYNC)) {
607*52889Sbostic 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
608*52889Sbostic 			state->flags |= TRY_SYNC;
609*52889Sbostic 		} else
610*52889Sbostic 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
611*52889Sbostic 		state->buf = (char *)0;
612*52889Sbostic 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
613*52889Sbostic 		int cnt;
614*52889Sbostic 
615*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
616*52889Sbostic 
617*52889Sbostic 		/* setup to write first chunk */
618*52889Sbostic 		state->flags |= DMA_OUT;
619*52889Sbostic 		state->buf = scsicmd->buf;
620*52889Sbostic 		cnt = state->dmaBufSize - len;
621*52889Sbostic 		if (cnt > state->buflen)
622*52889Sbostic 			cnt = state->buflen;
623*52889Sbostic 		else printf("can't write in one chunk cnt %d buflen %d\n",
624*52889Sbostic 			cnt, state->buflen); /* XXX */
625*52889Sbostic 		state->dmalen = cnt;
626*52889Sbostic 		bcopy(state->buf, state->dmaBufAddr + len, cnt);
627*52889Sbostic 	} else {
628*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
629*52889Sbostic 		state->buf = scsicmd->buf;
630*52889Sbostic 		state->flags |= DMA_IN;
631*52889Sbostic 	}
632*52889Sbostic 
633*52889Sbostic 	/* preload the FIFO with the message to be sent */
634*52889Sbostic 	regs->asc_fifo = /* SCSI_IDENTIFY */ SCSI_DIS_REC_IDENTIFY;
635*52889Sbostic 
636*52889Sbostic 	/* start the asc */
637*52889Sbostic 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
638*52889Sbostic 	ASC_TC_PUT(regs, len);
639*52889Sbostic 
640*52889Sbostic 	regs->asc_dbus_id = target;
641*52889Sbostic 	regs->asc_syn_p = state->sync_period;
642*52889Sbostic 	regs->asc_syn_o = state->sync_offset;
643*52889Sbostic 
644*52889Sbostic 	if (state->flags & TRY_SYNC)
645*52889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA;
646*52889Sbostic 	else
647*52889Sbostic 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
648*52889Sbostic }
649*52889Sbostic 
650*52889Sbostic /*
651*52889Sbostic  * Interrupt routine
652*52889Sbostic  *	Take interrupts from the chip
653*52889Sbostic  *
654*52889Sbostic  * Implementation:
655*52889Sbostic  *	Move along the current command's script if
656*52889Sbostic  *	all is well, invoke error handler if not.
657*52889Sbostic  */
658*52889Sbostic void
659*52889Sbostic asc_intr(unit)
660*52889Sbostic 	int unit;
661*52889Sbostic {
662*52889Sbostic 	register asc_softc_t asc = &asc_softc[unit];
663*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
664*52889Sbostic 	register State *state;
665*52889Sbostic 	register script_t *scpt;
666*52889Sbostic 	register int ss, ir, status;
667*52889Sbostic 
668*52889Sbostic again:
669*52889Sbostic 	/* collect ephemeral information */
670*52889Sbostic 	status = regs->asc_status;
671*52889Sbostic 	ss = regs->asc_ss;
672*52889Sbostic 	ir = regs->asc_intr;	/* this resets the previous two */
673*52889Sbostic 	scpt = asc->script;
674*52889Sbostic 
675*52889Sbostic #ifdef DEBUG
676*52889Sbostic 	asc_logp->status = PACK(unit, status, ss, ir);
677*52889Sbostic 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
678*52889Sbostic 	asc_logp->state = scpt - asc_scripts;
679*52889Sbostic 	asc_logp->msg = -1;
680*52889Sbostic 	if (++asc_logp >= &asc_log[NLOG])
681*52889Sbostic 		asc_logp = asc_log;
682*52889Sbostic 	if (asc_debug > 2)
683*52889Sbostic 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
684*52889Sbostic 			status, ss, ir, scpt - asc_scripts, scpt->condition);
685*52889Sbostic #endif
686*52889Sbostic 
687*52889Sbostic 	/* check the expected state */
688*52889Sbostic 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
689*52889Sbostic 		/*
690*52889Sbostic 		 * Perform the appropriate operation, then proceed.
691*52889Sbostic 		 */
692*52889Sbostic 		if ((*scpt->action)(asc, status, ss, ir)) {
693*52889Sbostic 			regs->asc_cmd = scpt->command;
694*52889Sbostic 			asc->script = scpt->next;
695*52889Sbostic 		}
696*52889Sbostic 		goto done;
697*52889Sbostic 	}
698*52889Sbostic 
699*52889Sbostic 	/* check for message in or out */
700*52889Sbostic 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
701*52889Sbostic 		register int len, fifo;
702*52889Sbostic 
703*52889Sbostic 		state = &asc->st[asc->target];
704*52889Sbostic 		switch (ASC_PHASE(status)) {
705*52889Sbostic 		case ASC_PHASE_MSG_IN:
706*52889Sbostic 			break;
707*52889Sbostic 
708*52889Sbostic 		case ASC_PHASE_MSG_OUT:
709*52889Sbostic 			regs->asc_fifo = state->msg_out;
710*52889Sbostic 			state->msg_out = SCSI_NO_OP;
711*52889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
712*52889Sbostic 			goto done;
713*52889Sbostic 
714*52889Sbostic 		case ASC_PHASE_STATUS:
715*52889Sbostic 			/* probably an error in the SCSI command */
716*52889Sbostic 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
717*52889Sbostic 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
718*52889Sbostic 			goto done;
719*52889Sbostic 
720*52889Sbostic 		default:
721*52889Sbostic 			goto abort;
722*52889Sbostic 		}
723*52889Sbostic 
724*52889Sbostic 		if (state->script)
725*52889Sbostic 			goto abort;
726*52889Sbostic 
727*52889Sbostic 		/* check for DMA in progress */
728*52889Sbostic 		ASC_TC_GET(regs, len);
729*52889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
730*52889Sbostic 		/* flush any data in the FIFO */
731*52889Sbostic 		if (fifo) {
732*52889Sbostic 			printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n",
733*52889Sbostic 				state->flags, state->dmalen,
734*52889Sbostic 				len, fifo); /* XXX */
735*52889Sbostic 			len += fifo;
736*52889Sbostic 			regs->asc_cmd = ASC_CMD_FLUSH;
737*52889Sbostic 			MachEmptyWriteBuffer();
738*52889Sbostic 		}
739*52889Sbostic 		if (len) {
740*52889Sbostic 			/* save number of bytes still to be sent or received */
741*52889Sbostic 			state->dmaresid = len;
742*52889Sbostic 			/* setup state to resume to */
743*52889Sbostic 			if (state->flags & DMA_IN)
744*52889Sbostic 				state->script =
745*52889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
746*52889Sbostic 			else if (state->flags & DMA_OUT)
747*52889Sbostic 				state->script =
748*52889Sbostic 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
749*52889Sbostic 			else
750*52889Sbostic 				state->script = asc->script;
751*52889Sbostic 		} else {
752*52889Sbostic 			/* setup state to resume to */
753*52889Sbostic 			if (state->flags & DMA_IN)
754*52889Sbostic 				state->script = &asc_scripts[SCRIPT_RESUME_IN];
755*52889Sbostic 			else if (state->flags & DMA_OUT)
756*52889Sbostic 				state->script = &asc_scripts[SCRIPT_RESUME_OUT];
757*52889Sbostic 			else
758*52889Sbostic 				state->script = asc->script;
759*52889Sbostic 		}
760*52889Sbostic 
761*52889Sbostic 		/* setup to receive a message */
762*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
763*52889Sbostic 		state->msglen = 0;
764*52889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO;
765*52889Sbostic 		goto done;
766*52889Sbostic 	}
767*52889Sbostic 
768*52889Sbostic 	/* check for SCSI bus reset */
769*52889Sbostic 	if (ir & ASC_INT_RESET) {
770*52889Sbostic 		register int i;
771*52889Sbostic 
772*52889Sbostic 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
773*52889Sbostic 		/* need to flush any pending commands */
774*52889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
775*52889Sbostic 			if (!asc->cmd[i])
776*52889Sbostic 				continue;
777*52889Sbostic 			asc->st[i].error = EIO;
778*52889Sbostic 			asc_end(asc, 0, 0, 0);
779*52889Sbostic 		}
780*52889Sbostic 		/* rearbitrate synchronous offset */
781*52889Sbostic 		for (i = 0; i < ASC_NCMD; i++) {
782*52889Sbostic 			asc->st[i].sync_offset = 0;
783*52889Sbostic 			asc->st[i].flags = 0;
784*52889Sbostic 		}
785*52889Sbostic 		asc->target = -1;
786*52889Sbostic 		return;
787*52889Sbostic 	}
788*52889Sbostic 
789*52889Sbostic 	/* check for command errors */
790*52889Sbostic 	if (ir & ASC_INT_ILL)
791*52889Sbostic 		goto abort;
792*52889Sbostic 
793*52889Sbostic 	/* check for disconnect */
794*52889Sbostic 	if (ir & ASC_INT_DISC) {
795*52889Sbostic 		state = &asc->st[asc->target];
796*52889Sbostic 		if (state->flags & DISCONN) {
797*52889Sbostic 			if (state->script)
798*52889Sbostic 				goto abort;
799*52889Sbostic 			state->script = asc->script;
800*52889Sbostic 			asc->target = -1;
801*52889Sbostic 			asc->state = ASC_STATE_RESEL;
802*52889Sbostic 			asc->script = &asc_scripts[SCRIPT_RESEL];
803*52889Sbostic 			regs->asc_cmd = ASC_CMD_ENABLE_SEL;
804*52889Sbostic 			goto done;
805*52889Sbostic 		}
806*52889Sbostic 
807*52889Sbostic 		switch (ASC_SS(ss)) {
808*52889Sbostic 		case 0: /* device did not respond */
809*52889Sbostic 			state->error = ENXIO;
810*52889Sbostic 			asc_end(asc, status, ss, ir);
811*52889Sbostic 			return;
812*52889Sbostic 
813*52889Sbostic 		default:
814*52889Sbostic 			goto abort;
815*52889Sbostic 		}
816*52889Sbostic 	}
817*52889Sbostic 
818*52889Sbostic 	/* check for reselect */
819*52889Sbostic 	if (ir & ASC_INT_RESEL) {
820*52889Sbostic 		unsigned fifo, id, msg;
821*52889Sbostic 
822*52889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
823*52889Sbostic 		if (fifo < 2)
824*52889Sbostic 			goto abort;
825*52889Sbostic 		/* read unencoded SCSI ID and convert to binary */
826*52889Sbostic 		msg = regs->asc_fifo & asc->myidmask;
827*52889Sbostic 		for (id = 0; (msg & 1) == 0; id++)
828*52889Sbostic 			msg >>= 1;
829*52889Sbostic 		/* read identify message */
830*52889Sbostic 		msg = regs->asc_fifo;
831*52889Sbostic #ifdef DEBUG
832*52889Sbostic 		if (asc_logp == asc_log)
833*52889Sbostic 			asc_log[NLOG - 1].msg = msg;
834*52889Sbostic 		else
835*52889Sbostic 			asc_logp[-1].msg = msg;
836*52889Sbostic #endif
837*52889Sbostic 		if (asc->state != ASC_STATE_RESEL)
838*52889Sbostic 			goto abort;
839*52889Sbostic 		asc->state = ASC_STATE_BUSY;
840*52889Sbostic 		asc->target = id;
841*52889Sbostic 		state = &asc->st[id];
842*52889Sbostic 		asc->script = state->script;
843*52889Sbostic 		state->script = (script_t *)0;
844*52889Sbostic 		if (!(state->flags & DISCONN))
845*52889Sbostic 			goto abort;
846*52889Sbostic 		state->flags &= ~DISCONN;
847*52889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
848*52889Sbostic 		goto done;
849*52889Sbostic 	}
850*52889Sbostic 
851*52889Sbostic 	/* check if we are being selected as a target */
852*52889Sbostic 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
853*52889Sbostic 		goto abort;
854*52889Sbostic 
855*52889Sbostic 	/* must be just a ASC_INT_FC */
856*52889Sbostic done:
857*52889Sbostic 	MachEmptyWriteBuffer();
858*52889Sbostic 	if (regs->asc_status & ASC_CSR_INT)
859*52889Sbostic 		goto again;
860*52889Sbostic 	return;
861*52889Sbostic 
862*52889Sbostic abort:
863*52889Sbostic #ifdef DEBUG
864*52889Sbostic 	asc_DumpLog("asc_intr");
865*52889Sbostic #endif
866*52889Sbostic #if 0
867*52889Sbostic 	panic("asc_intr");
868*52889Sbostic #else
869*52889Sbostic 	for (;;);
870*52889Sbostic #endif
871*52889Sbostic }
872*52889Sbostic 
873*52889Sbostic /*
874*52889Sbostic  * All the many little things that the interrupt
875*52889Sbostic  * routine might switch to.
876*52889Sbostic  */
877*52889Sbostic 
878*52889Sbostic /* ARGSUSED */
879*52889Sbostic static int
880*52889Sbostic script_nop(asc, status, ss, ir)
881*52889Sbostic 	register asc_softc_t asc;
882*52889Sbostic 	register int status, ss, ir;
883*52889Sbostic {
884*52889Sbostic 	return (1);
885*52889Sbostic }
886*52889Sbostic 
887*52889Sbostic /* ARGSUSED */
888*52889Sbostic static int
889*52889Sbostic asc_get_status(asc, status, ss, ir)
890*52889Sbostic 	register asc_softc_t asc;
891*52889Sbostic 	register int status, ss, ir;
892*52889Sbostic {
893*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
894*52889Sbostic 	register int data;
895*52889Sbostic 
896*52889Sbostic 	/*
897*52889Sbostic 	 * Get the last two bytes in the FIFO.
898*52889Sbostic 	 */
899*52889Sbostic 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
900*52889Sbostic 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
901*52889Sbostic 		if (data < 2) {
902*52889Sbostic 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
903*52889Sbostic 			return (0);
904*52889Sbostic 		}
905*52889Sbostic 		do {
906*52889Sbostic 			data = regs->asc_fifo;
907*52889Sbostic 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
908*52889Sbostic 	}
909*52889Sbostic 
910*52889Sbostic 	/* save the status byte */
911*52889Sbostic 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
912*52889Sbostic #ifdef DEBUG
913*52889Sbostic 	if (asc_logp == asc_log)
914*52889Sbostic 		asc_log[NLOG - 1].msg = data;
915*52889Sbostic 	else
916*52889Sbostic 		asc_logp[-1].msg = data;
917*52889Sbostic #endif
918*52889Sbostic 
919*52889Sbostic 	/* get the (presumed) command_complete message */
920*52889Sbostic 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
921*52889Sbostic 		return (1);
922*52889Sbostic 
923*52889Sbostic #ifdef DEBUG
924*52889Sbostic 	printf("asc_get_status: status %x cmd %x\n",
925*52889Sbostic 		asc->st[asc->target].statusByte, data);
926*52889Sbostic 	asc_DumpLog("asc_get_status");
927*52889Sbostic #endif
928*52889Sbostic 	return (0);
929*52889Sbostic }
930*52889Sbostic 
931*52889Sbostic /* ARGSUSED */
932*52889Sbostic static int
933*52889Sbostic asc_end(asc, status, ss, ir)
934*52889Sbostic 	register asc_softc_t asc;
935*52889Sbostic 	register int status, ss, ir;
936*52889Sbostic {
937*52889Sbostic 	register ScsiCmd *scsicmd;
938*52889Sbostic 	register State *state;
939*52889Sbostic 	register int i, target;
940*52889Sbostic 
941*52889Sbostic 	asc->state = ASC_STATE_IDLE;
942*52889Sbostic 	target = asc->target;
943*52889Sbostic 	asc->target = -1;
944*52889Sbostic 	scsicmd = asc->cmd[target];
945*52889Sbostic 	asc->cmd[target] = (ScsiCmd *)0;
946*52889Sbostic 	state = &asc->st[target];
947*52889Sbostic 
948*52889Sbostic #ifdef DEBUG
949*52889Sbostic 	if (asc_debug > 1) {
950*52889Sbostic 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
951*52889Sbostic 			scsicmd->sd->sd_driver->d_name, target,
952*52889Sbostic 			scsicmd->cmd[0], state->error, state->buflen);
953*52889Sbostic 	}
954*52889Sbostic #endif
955*52889Sbostic #ifdef DIAGNOSTIC
956*52889Sbostic 	if (target < 0 || !scsicmd)
957*52889Sbostic 		panic("asc_end");
958*52889Sbostic #endif
959*52889Sbostic 
960*52889Sbostic 	/* look for disconnected devices */
961*52889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
962*52889Sbostic 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
963*52889Sbostic 			continue;
964*52889Sbostic 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
965*52889Sbostic 		asc->state = ASC_STATE_RESEL;
966*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESEL];
967*52889Sbostic 		break;
968*52889Sbostic 	}
969*52889Sbostic 
970*52889Sbostic 	/* look for another device that is ready */
971*52889Sbostic 	for (i = 0; i < ASC_NCMD; i++) {
972*52889Sbostic 		/* don't restart a disconnected command */
973*52889Sbostic 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
974*52889Sbostic 			continue;
975*52889Sbostic 		asc_startcmd(asc, i);
976*52889Sbostic 		break;
977*52889Sbostic 	}
978*52889Sbostic 
979*52889Sbostic 	/* signal device driver that the command is done */
980*52889Sbostic 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
981*52889Sbostic 		state->buflen, state->statusByte);
982*52889Sbostic 
983*52889Sbostic 	return (0);
984*52889Sbostic }
985*52889Sbostic 
986*52889Sbostic /* ARGSUSED */
987*52889Sbostic static int
988*52889Sbostic asc_dma_in(asc, status, ss, ir)
989*52889Sbostic 	register asc_softc_t asc;
990*52889Sbostic 	register int status, ss, ir;
991*52889Sbostic {
992*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
993*52889Sbostic 	register State *state = &asc->st[asc->target];
994*52889Sbostic 	register int len, fifo;
995*52889Sbostic 
996*52889Sbostic 	/* check for previous chunk in buffer */
997*52889Sbostic 	if (!(state->flags & FIRST_DMA)) {
998*52889Sbostic 		/*
999*52889Sbostic 		 * Only count bytes that have been copied to memory.
1000*52889Sbostic 		 * There may be some bytes in the FIFO if synchonous transfers
1001*52889Sbostic 		 * are in progress.
1002*52889Sbostic 		 */
1003*52889Sbostic 		ASC_TC_GET(regs, len);
1004*52889Sbostic 		len = state->dmalen - len;
1005*52889Sbostic 		bcopy(state->dmaBufAddr, state->buf, len);
1006*52889Sbostic 		state->buf += len;
1007*52889Sbostic 		state->buflen -= len;
1008*52889Sbostic 	} else
1009*52889Sbostic 		state->flags &= ~FIRST_DMA;
1010*52889Sbostic 
1011*52889Sbostic 	/* setup to start reading next chunk */
1012*52889Sbostic 	len = state->buflen;
1013*52889Sbostic 	if (len > state->dmaBufSize)
1014*52889Sbostic 		len = state->dmaBufSize;
1015*52889Sbostic 	state->dmalen = len;
1016*52889Sbostic 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr);
1017*52889Sbostic 	ASC_TC_PUT(regs, len);
1018*52889Sbostic 	if (len != state->buflen) {
1019*52889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1020*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESUME_IN];
1021*52889Sbostic 		return (0);
1022*52889Sbostic 	}
1023*52889Sbostic 	return (1);
1024*52889Sbostic }
1025*52889Sbostic 
1026*52889Sbostic /* ARGSUSED */
1027*52889Sbostic static int
1028*52889Sbostic asc_last_dma_in(asc, status, ss, ir)
1029*52889Sbostic 	register asc_softc_t asc;
1030*52889Sbostic 	register int status, ss, ir;
1031*52889Sbostic {
1032*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1033*52889Sbostic 	register State *state = &asc->st[asc->target];
1034*52889Sbostic 	register int len, fifo;
1035*52889Sbostic 
1036*52889Sbostic 	/* copy data from buffer to main memory */
1037*52889Sbostic 	ASC_TC_GET(regs, len);
1038*52889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1039*52889Sbostic #ifdef DEBUG
1040*52889Sbostic 	if (asc_debug > 2 || len || fifo) /* XXX */
1041*52889Sbostic 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1042*52889Sbostic 			state->buflen, state->dmalen, len, fifo);
1043*52889Sbostic #endif
1044*52889Sbostic 	if (fifo) {
1045*52889Sbostic 		regs->asc_cmd = ASC_CMD_FLUSH;
1046*52889Sbostic 		MachEmptyWriteBuffer();
1047*52889Sbostic 	}
1048*52889Sbostic 	len = state->dmalen - len;
1049*52889Sbostic 	state->buflen -= len;
1050*52889Sbostic 	bcopy(state->dmaBufAddr, state->buf, len);
1051*52889Sbostic 
1052*52889Sbostic 	return (1);
1053*52889Sbostic }
1054*52889Sbostic 
1055*52889Sbostic /* ARGSUSED */
1056*52889Sbostic static int
1057*52889Sbostic asc_resume_dma_in(asc, status, ss, ir)
1058*52889Sbostic 	register asc_softc_t asc;
1059*52889Sbostic 	register int status, ss, ir;
1060*52889Sbostic {
1061*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1062*52889Sbostic 	register State *state = &asc->st[asc->target];
1063*52889Sbostic 	register int len, off;
1064*52889Sbostic 
1065*52889Sbostic 	/* setup to finish reading the current chunk */
1066*52889Sbostic 	len = state->dmaresid;
1067*52889Sbostic 	off = state->dmalen - len;
1068*52889Sbostic 	if ((off & 1) && state->sync_offset) {
1069*52889Sbostic 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1070*52889Sbostic 			state->dmalen, len, off); /* XXX */
1071*52889Sbostic 		regs->asc_res_fifo = state->dmaBufAddr[off];
1072*52889Sbostic 	}
1073*52889Sbostic 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off);
1074*52889Sbostic 	ASC_TC_PUT(regs, len);
1075*52889Sbostic 	if (state->dmalen != state->buflen) {
1076*52889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1077*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESUME_IN];
1078*52889Sbostic 		return (0);
1079*52889Sbostic 	}
1080*52889Sbostic 	return (1);
1081*52889Sbostic }
1082*52889Sbostic 
1083*52889Sbostic /* ARGSUSED */
1084*52889Sbostic static int
1085*52889Sbostic asc_dma_out(asc, status, ss, ir)
1086*52889Sbostic 	register asc_softc_t asc;
1087*52889Sbostic 	register int status, ss, ir;
1088*52889Sbostic {
1089*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1090*52889Sbostic 	register State *state = &asc->st[asc->target];
1091*52889Sbostic 	register int len, fifo;
1092*52889Sbostic 
1093*52889Sbostic 	if (!(state->flags & FIRST_DMA)) {
1094*52889Sbostic 		/* check to be sure previous chunk was finished */
1095*52889Sbostic 		ASC_TC_GET(regs, len);
1096*52889Sbostic 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1097*52889Sbostic 		if (len || fifo)
1098*52889Sbostic 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1099*52889Sbostic 				state->buflen, state->dmalen, len, fifo); /* XXX */
1100*52889Sbostic 		len += fifo;
1101*52889Sbostic 		len = state->dmalen - len;
1102*52889Sbostic 		state->buflen -= len;
1103*52889Sbostic 		state->buf += len;
1104*52889Sbostic 
1105*52889Sbostic 		/* setup for this chunck */
1106*52889Sbostic 		len = state->buflen;
1107*52889Sbostic 		if (len > state->dmaBufSize)
1108*52889Sbostic 			len = state->dmaBufSize;
1109*52889Sbostic 		state->dmalen = len;
1110*52889Sbostic 		bcopy(state->buf, state->dmaBufAddr, len);
1111*52889Sbostic 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
1112*52889Sbostic 	} else
1113*52889Sbostic 		state->flags &= ~FIRST_DMA;
1114*52889Sbostic 
1115*52889Sbostic #ifdef DEBUG
1116*52889Sbostic 	if (asc_debug > 2)
1117*52889Sbostic 		printf("asc_dma_out: dmalen %d fifo %d\n",
1118*52889Sbostic 			state->dmalen,
1119*52889Sbostic 			regs->asc_flags & ASC_FLAGS_FIFO_CNT);
1120*52889Sbostic #endif
1121*52889Sbostic 	len = state->dmalen;
1122*52889Sbostic 	ASC_TC_PUT(regs, len);
1123*52889Sbostic 
1124*52889Sbostic 	/* check for next chunk */
1125*52889Sbostic 	if (len != state->buflen) {
1126*52889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1127*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESUME_OUT];
1128*52889Sbostic 		return (0);
1129*52889Sbostic 	}
1130*52889Sbostic 	return (1);
1131*52889Sbostic }
1132*52889Sbostic 
1133*52889Sbostic /* ARGSUSED */
1134*52889Sbostic static int
1135*52889Sbostic asc_last_dma_out(asc, status, ss, ir)
1136*52889Sbostic 	register asc_softc_t asc;
1137*52889Sbostic 	register int status, ss, ir;
1138*52889Sbostic {
1139*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1140*52889Sbostic 	register State *state = &asc->st[asc->target];
1141*52889Sbostic 	register int len, fifo;
1142*52889Sbostic 
1143*52889Sbostic 	len = state->dmalen;
1144*52889Sbostic 	ASC_TC_GET(regs, len);
1145*52889Sbostic 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1146*52889Sbostic 
1147*52889Sbostic #ifdef DEBUG
1148*52889Sbostic 	if (asc_debug > 2)
1149*52889Sbostic 		printf("asc_last_dma_out: dmalen %d tc %d fifo %d\n",
1150*52889Sbostic 			state->dmalen, len, fifo);
1151*52889Sbostic #endif
1152*52889Sbostic 
1153*52889Sbostic 	if (len || fifo)
1154*52889Sbostic 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1155*52889Sbostic 			state->buflen, state->dmalen, len, fifo); /* XXX */
1156*52889Sbostic 	len += fifo;
1157*52889Sbostic 	len = state->dmalen - len;
1158*52889Sbostic 	state->buflen -= len;
1159*52889Sbostic 	return (1);
1160*52889Sbostic }
1161*52889Sbostic 
1162*52889Sbostic /* ARGSUSED */
1163*52889Sbostic static int
1164*52889Sbostic asc_resume_dma_out(asc, status, ss, ir)
1165*52889Sbostic 	register asc_softc_t asc;
1166*52889Sbostic 	register int status, ss, ir;
1167*52889Sbostic {
1168*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1169*52889Sbostic 	register State *state = &asc->st[asc->target];
1170*52889Sbostic 	register int len, off;
1171*52889Sbostic 
1172*52889Sbostic 	/* setup to finish writing this chunk */
1173*52889Sbostic 	len = state->dmaresid;
1174*52889Sbostic 	off = state->dmalen - len;
1175*52889Sbostic 	if (off & 1) {
1176*52889Sbostic 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1177*52889Sbostic 			state->dmalen, len, off); /* XXX */
1178*52889Sbostic 		regs->asc_fifo = state->dmaBufAddr[off];
1179*52889Sbostic 		off++;
1180*52889Sbostic 		len--;
1181*52889Sbostic 	}
1182*52889Sbostic 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off);
1183*52889Sbostic 	ASC_TC_PUT(regs, len);
1184*52889Sbostic 	if (state->dmalen != state->buflen) {
1185*52889Sbostic 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1186*52889Sbostic 		asc->script = &asc_scripts[SCRIPT_RESUME_OUT];
1187*52889Sbostic 		return (0);
1188*52889Sbostic 	}
1189*52889Sbostic 	return (1);
1190*52889Sbostic }
1191*52889Sbostic 
1192*52889Sbostic /* ARGSUSED */
1193*52889Sbostic static int
1194*52889Sbostic asc_sendsync(asc, status, ss, ir)
1195*52889Sbostic 	register asc_softc_t asc;
1196*52889Sbostic 	register int status, ss, ir;
1197*52889Sbostic {
1198*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1199*52889Sbostic 
1200*52889Sbostic 	/*
1201*52889Sbostic 	 * Phase is MSG_OUT here.
1202*52889Sbostic 	 * Try sync negotiation, unless prohibited
1203*52889Sbostic 	 */
1204*52889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1205*52889Sbostic 	MachEmptyWriteBuffer();
1206*52889Sbostic 	regs->asc_fifo = 3;
1207*52889Sbostic 	MachEmptyWriteBuffer();
1208*52889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1209*52889Sbostic 	MachEmptyWriteBuffer();
1210*52889Sbostic 	regs->asc_fifo = SCSI_MIN_PERIOD;
1211*52889Sbostic 	MachEmptyWriteBuffer();
1212*52889Sbostic 	regs->asc_fifo = ASC_MAX_OFFSET;
1213*52889Sbostic 	return (1);
1214*52889Sbostic }
1215*52889Sbostic 
1216*52889Sbostic /* ARGSUSED */
1217*52889Sbostic static int
1218*52889Sbostic asc_replysync(asc, status, ss, ir)
1219*52889Sbostic 	register asc_softc_t asc;
1220*52889Sbostic 	register int status, ss, ir;
1221*52889Sbostic {
1222*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1223*52889Sbostic 	register State *state = &asc->st[asc->target];
1224*52889Sbostic 
1225*52889Sbostic #ifdef DEBUG
1226*52889Sbostic 	if (asc_debug > 2)
1227*52889Sbostic 		printf("asc_replysync: %x %x\n",
1228*52889Sbostic 			asc_to_scsi_period[state->sync_period],
1229*52889Sbostic 			state->sync_offset);
1230*52889Sbostic #endif
1231*52889Sbostic 	/* send synchronous transfer in response to a request */
1232*52889Sbostic 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1233*52889Sbostic 	MachEmptyWriteBuffer();
1234*52889Sbostic 	regs->asc_fifo = 3;
1235*52889Sbostic 	MachEmptyWriteBuffer();
1236*52889Sbostic 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1237*52889Sbostic 	MachEmptyWriteBuffer();
1238*52889Sbostic 	regs->asc_fifo = asc_to_scsi_period[state->sync_period];
1239*52889Sbostic 	MachEmptyWriteBuffer();
1240*52889Sbostic 	regs->asc_fifo = state->sync_offset;
1241*52889Sbostic 	regs->asc_cmd = ASC_CMD_XFER_INFO;
1242*52889Sbostic 
1243*52889Sbostic 	/* return to the appropriate script */
1244*52889Sbostic 	if (!state->script) {
1245*52889Sbostic #ifdef DEBUG
1246*52889Sbostic 		asc_DumpLog("asc_replsync");
1247*52889Sbostic #endif
1248*52889Sbostic 		panic("asc_replysync");
1249*52889Sbostic 	}
1250*52889Sbostic 	asc->script = state->script;
1251*52889Sbostic 	state->script = (script_t *)0;
1252*52889Sbostic 	return (0);
1253*52889Sbostic }
1254*52889Sbostic 
1255*52889Sbostic /* ARGSUSED */
1256*52889Sbostic static int
1257*52889Sbostic asc_recvmsg(asc, status, ss, ir)
1258*52889Sbostic 	register asc_softc_t asc;
1259*52889Sbostic 	register int status, ss, ir;
1260*52889Sbostic {
1261*52889Sbostic 	register asc_regmap_t *regs = asc->regs;
1262*52889Sbostic 	register State *state = &asc->st[asc->target];
1263*52889Sbostic 	register int msg;
1264*52889Sbostic 	int i;
1265*52889Sbostic 
1266*52889Sbostic 	/* read one message byte */
1267*52889Sbostic 	msg = regs->asc_fifo;
1268*52889Sbostic #ifdef DEBUG
1269*52889Sbostic 	if (asc_logp == asc_log)
1270*52889Sbostic 		asc_log[NLOG - 1].msg = msg;
1271*52889Sbostic 	else
1272*52889Sbostic 		asc_logp[-1].msg = msg;
1273*52889Sbostic #endif
1274*52889Sbostic 
1275*52889Sbostic 	/* check for multi-byte message */
1276*52889Sbostic 	if (state->msglen != 0) {
1277*52889Sbostic 		/* first byte is the message length */
1278*52889Sbostic 		if (state->msglen < 0) {
1279*52889Sbostic 			state->msglen = msg;
1280*52889Sbostic 			return (1);
1281*52889Sbostic 		}
1282*52889Sbostic 		if (state->msgcnt >= state->msglen)
1283*52889Sbostic 			goto abort;
1284*52889Sbostic 		state->msg_in[state->msgcnt++] = msg;
1285*52889Sbostic 
1286*52889Sbostic 		/* did we just read the last byte of the message? */
1287*52889Sbostic 		if (state->msgcnt != state->msglen)
1288*52889Sbostic 			return (1);
1289*52889Sbostic 
1290*52889Sbostic 		/* process an extended message */
1291*52889Sbostic #ifdef DEBUG
1292*52889Sbostic 		if (asc_debug > 2)
1293*52889Sbostic 			printf("asc_recvmsg: msg %x %x %x\n",
1294*52889Sbostic 				state->msg_in[0],
1295*52889Sbostic 				state->msg_in[1],
1296*52889Sbostic 				state->msg_in[2]);
1297*52889Sbostic #endif
1298*52889Sbostic 		switch (state->msg_in[0]) {
1299*52889Sbostic 		case SCSI_SYNCHRONOUS_XFER:
1300*52889Sbostic 			state->flags |= DID_SYNC;
1301*52889Sbostic 			state->sync_offset = state->msg_in[2];
1302*52889Sbostic 
1303*52889Sbostic 			/* convert SCSI period to ASC period */
1304*52889Sbostic 			i = state->msg_in[1] / 10;
1305*52889Sbostic 			if (i < ASC_MIN_PERIOD)
1306*52889Sbostic 				i = ASC_MIN_PERIOD;
1307*52889Sbostic 			else if (i >= ASC_MAX_PERIOD) {
1308*52889Sbostic 				/* can't do sync transfer, period too long */
1309*52889Sbostic 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
1310*52889Sbostic 					asc - asc_softc, asc->target, i);
1311*52889Sbostic 				i = ASC_MAX_PERIOD;
1312*52889Sbostic 				state->sync_offset = 0;
1313*52889Sbostic 			}
1314*52889Sbostic 			if ((i * 10) != state->msg_in[1])
1315*52889Sbostic 				i++;
1316*52889Sbostic 			state->sync_period = i & 0x1F;
1317*52889Sbostic 
1318*52889Sbostic 			/*
1319*52889Sbostic 			 * If this is a request, check minimums and
1320*52889Sbostic 			 * send back an acknowledge.
1321*52889Sbostic 			 */
1322*52889Sbostic 			if (!(state->flags & TRY_SYNC)) {
1323*52889Sbostic 				regs->asc_cmd = ASC_CMD_SET_ATN;
1324*52889Sbostic 				MachEmptyWriteBuffer();
1325*52889Sbostic 
1326*52889Sbostic 				if (state->sync_period < ASC_MIN_PERIOD)
1327*52889Sbostic 					state->sync_period =
1328*52889Sbostic 						ASC_MIN_PERIOD;
1329*52889Sbostic 				if (state->sync_offset > ASC_MAX_OFFSET)
1330*52889Sbostic 					state->sync_offset =
1331*52889Sbostic 						ASC_MAX_OFFSET;
1332*52889Sbostic 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1333*52889Sbostic 				regs->asc_syn_p = state->sync_period;
1334*52889Sbostic 				regs->asc_syn_o = state->sync_offset;
1335*52889Sbostic 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
1336*52889Sbostic 				return (0);
1337*52889Sbostic 			}
1338*52889Sbostic 
1339*52889Sbostic 			regs->asc_syn_p = state->sync_period;
1340*52889Sbostic 			regs->asc_syn_o = state->sync_offset;
1341*52889Sbostic 			goto done;
1342*52889Sbostic 
1343*52889Sbostic 		default:
1344*52889Sbostic 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
1345*52889Sbostic 				asc - asc_softc, asc->target,
1346*52889Sbostic 				state->msg_in[0]);
1347*52889Sbostic 			goto reject;
1348*52889Sbostic 		}
1349*52889Sbostic 	}
1350*52889Sbostic 
1351*52889Sbostic 	/* process first byte of a message */
1352*52889Sbostic #ifdef DEBUG
1353*52889Sbostic 	if (asc_debug > 2)
1354*52889Sbostic 		printf("asc_recvmsg: msg %x\n", msg);
1355*52889Sbostic #endif
1356*52889Sbostic 	switch (msg) {
1357*52889Sbostic #if 0
1358*52889Sbostic 	case SCSI_MESSAGE_REJECT:
1359*52889Sbostic 		printf(" did not like SYNCH xfer "); /* XXX */
1360*52889Sbostic 		state->flags |= DID_SYNC;
1361*52889Sbostic 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1362*52889Sbostic 		status = asc_wait(regs, ASC_CSR_INT);
1363*52889Sbostic 		ir = regs->asc_intr;
1364*52889Sbostic 		/* some just break out here, some dont */
1365*52889Sbostic 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1366*52889Sbostic 			regs->asc_fifo = SCSI_ABORT;
1367*52889Sbostic 			regs->asc_cmd = ASC_CMD_XFER_INFO;
1368*52889Sbostic 			status = asc_wait(regs, ASC_CSR_INT);
1369*52889Sbostic 			ir = regs->asc_intr;
1370*52889Sbostic 		}
1371*52889Sbostic 		if (ir & ASC_INT_DISC) {
1372*52889Sbostic 			asc_end(asc, status, 0, ir);
1373*52889Sbostic 			return (0);
1374*52889Sbostic 		}
1375*52889Sbostic 		goto status;
1376*52889Sbostic #endif
1377*52889Sbostic 
1378*52889Sbostic 	case SCSI_EXTENDED_MSG: /* read an extended message */
1379*52889Sbostic 		/* setup to read message length next */
1380*52889Sbostic 		state->msglen = -1;
1381*52889Sbostic 		state->msgcnt = 0;
1382*52889Sbostic 		return (1);
1383*52889Sbostic 
1384*52889Sbostic 	case SCSI_NO_OP:
1385*52889Sbostic 		break;
1386*52889Sbostic 
1387*52889Sbostic 	case SCSI_SAVE_DATA_POINTER:
1388*52889Sbostic 		/* expect another message */
1389*52889Sbostic 		return (1);
1390*52889Sbostic 
1391*52889Sbostic 	case SCSI_RESTORE_POINTERS:
1392*52889Sbostic 		/*
1393*52889Sbostic 		 * Need to do the following if resuming synchonous data in
1394*52889Sbostic 		 * on an odd byte boundary.
1395*52889Sbostic 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1396*52889Sbostic 		 */
1397*52889Sbostic 		break;
1398*52889Sbostic 
1399*52889Sbostic 	case SCSI_DISCONNECT:
1400*52889Sbostic 		if (state->flags & DISCONN)
1401*52889Sbostic 			goto abort;
1402*52889Sbostic 		state->flags |= DISCONN;
1403*52889Sbostic 		break;
1404*52889Sbostic 
1405*52889Sbostic 	default:
1406*52889Sbostic 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
1407*52889Sbostic 			asc - asc_softc, asc->target, msg);
1408*52889Sbostic 	reject:
1409*52889Sbostic 		/* request a message out before acknowledging this message */
1410*52889Sbostic 		state->msg_out = SCSI_MESSAGE_REJECT;
1411*52889Sbostic 		regs->asc_cmd = ASC_CMD_SET_ATN;
1412*52889Sbostic 		MachEmptyWriteBuffer();
1413*52889Sbostic 	}
1414*52889Sbostic 
1415*52889Sbostic done:
1416*52889Sbostic 	/* return to original script */
1417*52889Sbostic 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
1418*52889Sbostic 	if (!state->script) {
1419*52889Sbostic 	abort:
1420*52889Sbostic #ifdef DEBUG
1421*52889Sbostic 		asc_DumpLog("asc_recvmsg");
1422*52889Sbostic #endif
1423*52889Sbostic 		panic("asc_recvmsg");
1424*52889Sbostic 	}
1425*52889Sbostic 	asc->script = state->script;
1426*52889Sbostic 	state->script = (script_t *)0;
1427*52889Sbostic 	return (0);
1428*52889Sbostic }
1429*52889Sbostic 
1430*52889Sbostic #ifdef DEBUG
1431*52889Sbostic asc_DumpLog(str)
1432*52889Sbostic 	char *str;
1433*52889Sbostic {
1434*52889Sbostic 	register struct asc_log *lp;
1435*52889Sbostic 	register u_int status;
1436*52889Sbostic 
1437*52889Sbostic 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
1438*52889Sbostic 		asc_debug_bn, asc_debug_sz);
1439*52889Sbostic 	lp = asc_logp + 1;
1440*52889Sbostic 	if (lp > &asc_log[NLOG])
1441*52889Sbostic 		lp = asc_log;
1442*52889Sbostic 	while (lp != asc_logp) {
1443*52889Sbostic 		status = lp->status;
1444*52889Sbostic 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
1445*52889Sbostic 			status >> 24,
1446*52889Sbostic 			lp->target,
1447*52889Sbostic 			(status >> 16) & 0xFF,
1448*52889Sbostic 			(status >> 8) & 0xFF,
1449*52889Sbostic 			status & 0XFF,
1450*52889Sbostic 			lp->state,
1451*52889Sbostic 			asc_scripts[lp->state].condition,
1452*52889Sbostic 			lp->msg);
1453*52889Sbostic 		if (++lp >= &asc_log[NLOG])
1454*52889Sbostic 			lp = asc_log;
1455*52889Sbostic 	}
1456*52889Sbostic }
1457*52889Sbostic #endif
1458*52889Sbostic 
1459*52889Sbostic #endif	/* NASC > 0 */
1460