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