xref: /original-bsd/sys/pmax/dev/asc.c (revision 4670e840)
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 and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)asc.c	7.10 (Berkeley) 03/08/93
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 <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/dkstat.h>
100 #include <sys/buf.h>
101 #include <sys/conf.h>
102 #include <sys/errno.h>
103 
104 #include <machine/machConst.h>
105 
106 #include <pmax/dev/device.h>
107 #include <pmax/dev/scsi.h>
108 #include <pmax/dev/ascreg.h>
109 
110 #include <pmax/pmax/asic.h>
111 #include <pmax/pmax/kmin.h>
112 #include <pmax/pmax/pmaxtype.h>
113 
114 #define	readback(a)	{ register int foo; foo = (a); }
115 extern int pmax_boardtype;
116 
117 /*
118  * In 4ns ticks.
119  */
120 int	asc_to_scsi_period[] = {
121 	32,
122 	33,
123 	34,
124 	35,
125 	5,
126 	5,
127 	6,
128 	7,
129 	8,
130 	9,
131 	10,
132 	11,
133 	12,
134 	13,
135 	14,
136 	15,
137 	16,
138 	17,
139 	18,
140 	19,
141 	20,
142 	21,
143 	22,
144 	23,
145 	24,
146 	25,
147 	26,
148 	27,
149 	28,
150 	29,
151 	30,
152 	31,
153 };
154 
155 /*
156  * Internal forward declarations.
157  */
158 static void asc_reset();
159 static void asc_startcmd();
160 
161 #ifdef DEBUG
162 int	asc_debug = 1;
163 int	asc_debug_cmd;
164 int	asc_debug_bn;
165 int	asc_debug_sz;
166 #define NLOG 16
167 struct asc_log {
168 	u_int	status;
169 	u_char	state;
170 	u_char	msg;
171 	int	target;
172 } asc_log[NLOG], *asc_logp = asc_log;
173 #define PACK(unit, status, ss, ir) \
174 	((unit << 24) | (status << 16) | (ss << 8) | ir)
175 #endif
176 
177 /*
178  * Scripts are entries in a state machine table.
179  * A script has four parts: a pre-condition, an action, a command to the chip,
180  * and an index into asc_scripts for the next state. The first triggers error
181  * handling if not satisfied and in our case it is formed by the
182  * values of the interrupt register and status register, this
183  * basically captures the phase of the bus and the TC and BS
184  * bits.  The action part is just a function pointer, and the
185  * command is what the 53C94 should be told to do at the end
186  * of the action processing.  This command is only issued and the
187  * script proceeds if the action routine returns TRUE.
188  * See asc_intr() for how and where this is all done.
189  */
190 typedef struct script {
191 	int		condition;	/* expected state at interrupt time */
192 	int		(*action)();	/* extra operations */
193 	int		command;	/* command to the chip */
194 	struct script	*next;		/* index into asc_scripts for next state */
195 } script_t;
196 
197 /* Matching on the condition value */
198 #define	SCRIPT_MATCH(ir, csr)		((ir) | (ASC_PHASE(csr) << 8))
199 
200 /* forward decls of script actions */
201 static int script_nop();		/* when nothing needed */
202 static int asc_end();			/* all come to an end */
203 static int asc_get_status();		/* get status from target */
204 static int asc_dma_in();		/* start reading data from target */
205 static int asc_last_dma_in();		/* cleanup after all data is read */
206 static int asc_resume_in();		/* resume data in after a message */
207 static int asc_resume_dma_in();		/* resume DMA after a disconnect */
208 static int asc_dma_out();		/* send data to target via dma */
209 static int asc_last_dma_out();		/* cleanup after all data is written */
210 static int asc_resume_out();		/* resume data out after a message */
211 static int asc_resume_dma_out();	/* resume DMA after a disconnect */
212 static int asc_sendsync();		/* negotiate sync xfer */
213 static int asc_replysync();		/* negotiate sync xfer */
214 static int asc_msg_in();		/* process a message byte */
215 static int asc_disconnect();		/* process an expected disconnect */
216 
217 /* Define the index into asc_scripts for various state transitions */
218 #define	SCRIPT_DATA_IN		0
219 #define	SCRIPT_CONTINUE_IN	2
220 #define	SCRIPT_DATA_OUT		3
221 #define	SCRIPT_CONTINUE_OUT	5
222 #define	SCRIPT_SIMPLE		6
223 #define	SCRIPT_GET_STATUS	7
224 #define	SCRIPT_MSG_IN		9
225 #define	SCRIPT_REPLY_SYNC	11
226 #define	SCRIPT_TRY_SYNC		12
227 #define	SCRIPT_DISCONNECT	15
228 #define	SCRIPT_RESEL		16
229 #define	SCRIPT_RESUME_IN	17
230 #define	SCRIPT_RESUME_DMA_IN	18
231 #define	SCRIPT_RESUME_OUT	19
232 #define	SCRIPT_RESUME_DMA_OUT	20
233 #define	SCRIPT_RESUME_NO_DATA	21
234 
235 /*
236  * Scripts
237  */
238 script_t asc_scripts[] = {
239 	/* start data in */
240 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI),	/*  0 */
241 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
242 		&asc_scripts[SCRIPT_DATA_IN + 1]},
243 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  1 */
244 		asc_last_dma_in, ASC_CMD_I_COMPLETE,
245 		&asc_scripts[SCRIPT_GET_STATUS]},
246 
247 	/* continue data in after a chunk is finished */
248 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/*  2 */
249 		asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
250 		&asc_scripts[SCRIPT_DATA_IN + 1]},
251 
252 	/* start data out */
253 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO),	/*  3 */
254 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
255 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
256 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/*  4 */
257 		asc_last_dma_out, ASC_CMD_I_COMPLETE,
258 		&asc_scripts[SCRIPT_GET_STATUS]},
259 
260 	/* continue data out after a chunk is finished */
261 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/*  5 */
262 		asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
263 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
264 
265 	/* simple command with no data transfer */
266 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS),	/*  6 */
267 		script_nop, ASC_CMD_I_COMPLETE,
268 		&asc_scripts[SCRIPT_GET_STATUS]},
269 
270 	/* get status and finish command */
271 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  7 */
272 		asc_get_status, ASC_CMD_MSG_ACPT,
273 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
274 	{SCRIPT_MATCH(ASC_INT_DISC, 0),					/*  8 */
275 		asc_end, ASC_CMD_NOP,
276 		&asc_scripts[SCRIPT_GET_STATUS + 1]},
277 
278 	/* message in */
279 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/*  9 */
280 		asc_msg_in, ASC_CMD_MSG_ACPT,
281 		&asc_scripts[SCRIPT_MSG_IN + 1]},
282 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 10 */
283 		script_nop, ASC_CMD_XFER_INFO,
284 		&asc_scripts[SCRIPT_MSG_IN]},
285 
286 	/* send synchonous negotiation reply */
287 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT),			/* 11 */
288 		asc_replysync, ASC_CMD_XFER_INFO,
289 		&asc_scripts[SCRIPT_REPLY_SYNC]},
290 
291 	/* try to negotiate synchonous transfer parameters */
292 	{SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT),	/* 12 */
293 		asc_sendsync, ASC_CMD_XFER_INFO,
294 		&asc_scripts[SCRIPT_TRY_SYNC + 1]},
295 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN),			/* 13 */
296 		script_nop, ASC_CMD_XFER_INFO,
297 		&asc_scripts[SCRIPT_MSG_IN]},
298 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND),			/* 14 */
299 		script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
300 		&asc_scripts[SCRIPT_RESUME_NO_DATA]},
301 
302 	/* handle a disconnect */
303 	{SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO),			/* 15 */
304 		asc_disconnect, ASC_CMD_ENABLE_SEL,
305 		&asc_scripts[SCRIPT_RESEL]},
306 
307 	/* reselect sequence: this is just a placeholder so match fails */
308 	{SCRIPT_MATCH(0, ASC_PHASE_MSG_IN),				/* 16 */
309 		script_nop, ASC_CMD_MSG_ACPT,
310 		&asc_scripts[SCRIPT_RESEL]},
311 
312 	/* resume data in after a message */
313 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 17 */
314 		asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
315 		&asc_scripts[SCRIPT_DATA_IN + 1]},
316 
317 	/* resume partial DMA data in after a message */
318 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI),			/* 18 */
319 		asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
320 		&asc_scripts[SCRIPT_DATA_IN + 1]},
321 
322 	/* resume data out after a message */
323 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 19 */
324 		asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
325 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
326 
327 	/* resume partial DMA data out after a message */
328 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO),			/* 20 */
329 		asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
330 		&asc_scripts[SCRIPT_DATA_OUT + 1]},
331 
332 	/* resume after a message when there is no more data */
333 	{SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS),			/* 21 */
334 		script_nop, ASC_CMD_I_COMPLETE,
335 		&asc_scripts[SCRIPT_GET_STATUS]},
336 };
337 
338 /*
339  * State kept for each active SCSI device.
340  */
341 typedef struct scsi_state {
342 	script_t *script;	/* saved script while processing error */
343 	int	statusByte;	/* status byte returned during STATUS_PHASE */
344 	int	error;		/* errno to pass back to device driver */
345 	u_char	*dmaBufAddr;	/* DMA buffer address */
346 	u_int	dmaBufSize;	/* DMA buffer size */
347 	int	dmalen;		/* amount to transfer in this chunk */
348 	int	dmaresid;	/* amount not transfered if chunk suspended */
349 	int	buflen;		/* total remaining amount of data to transfer */
350 	char	*buf;		/* current pointer within scsicmd->buf */
351 	int	flags;		/* see below */
352 	int	msglen;		/* number of message bytes to read */
353 	int	msgcnt;		/* number of message bytes received */
354 	u_char	sync_period;	/* DMA synchronous period */
355 	u_char	sync_offset;	/* DMA synchronous xfer offset or 0 if async */
356 	u_char	msg_out;	/* next MSG_OUT byte to send */
357 	u_char	msg_in[16];	/* buffer for multibyte messages */
358 } State;
359 
360 /* state flags */
361 #define DISCONN		0x01	/* true if currently disconnected from bus */
362 #define DMA_IN_PROGRESS	0x02	/* true if data DMA started */
363 #define DMA_IN		0x04	/* true if reading from SCSI device */
364 #define DMA_OUT		0x10	/* true if writing to SCSI device */
365 #define DID_SYNC	0x20	/* true if synchronous offset was negotiated */
366 #define TRY_SYNC	0x40	/* true if try neg. synchronous offset */
367 
368 /*
369  * State kept for each active SCSI host interface (53C94).
370  */
371 struct asc_softc {
372 	asc_regmap_t	*regs;		/* chip address */
373 	volatile int	*dmar;		/* DMA address register address */
374 	u_char		*buff;		/* RAM buffer address (uncached) */
375 	int		myid;		/* SCSI ID of this interface */
376 	int		myidmask;	/* ~(1 << myid) */
377 	int		state;		/* current SCSI connection state */
378 	int		target;		/* target SCSI ID if busy */
379 	script_t	*script;	/* next expected interrupt & action */
380 	ScsiCmd		*cmd[ASC_NCMD];	/* active command indexed by SCSI ID */
381 	State		st[ASC_NCMD];	/* state info for each active command */
382 	void		(*dma_start)();	/* Start dma routine */
383 	void		(*dma_end)();	/* End dma routine */
384 	u_char		*dma_next;
385 	int		dma_xfer;	/* Dma len still to go */
386 	int		min_period;	/* Min transfer period clk/byte */
387 	int		max_period;	/* Max transfer period clk/byte */
388 	int		ccf;		/* CCF, whatever that really is? */
389 	int		timeout_250;	/* 250ms timeout */
390 	int		tb_ticks;	/* 4ns. ticks/tb channel ticks */
391 } asc_softc[NASC];
392 
393 #define	ASC_STATE_IDLE		0	/* idle state */
394 #define	ASC_STATE_BUSY		1	/* selecting or currently connected */
395 #define ASC_STATE_TARGET	2	/* currently selected as target */
396 #define ASC_STATE_RESEL		3	/* currently waiting for reselect */
397 
398 typedef struct asc_softc *asc_softc_t;
399 
400 /*
401  * Dma operations.
402  */
403 #define	ASCDMA_READ	1
404 #define	ASCDMA_WRITE	2
405 static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();
406 extern u_long asc_iomem;
407 extern u_long asic_base;
408 
409 /*
410  * Definition of the controller for the auto-configuration program.
411  */
412 int	asc_probe();
413 void	asc_start();
414 void	asc_intr();
415 struct	driver ascdriver = {
416 	"asc", asc_probe, asc_start, 0, asc_intr,
417 };
418 
419 /*
420  * Test to see if device is present.
421  * Return true if found and initialized ok.
422  */
423 asc_probe(cp)
424 	register struct pmax_ctlr *cp;
425 {
426 	register asc_softc_t asc;
427 	register asc_regmap_t *regs;
428 	int unit, id, s, i;
429 	int bufsiz;
430 
431 	if ((unit = cp->pmax_unit) >= NASC)
432 		return (0);
433 	if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1))
434 		return (0);
435 	asc = &asc_softc[unit];
436 
437 	/*
438 	 * Initialize hw descriptor, cache some pointers
439 	 */
440 	asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94);
441 
442 	/*
443 	 * Set up machine dependencies.
444 	 * 1) how to do dma
445 	 * 2) timing based on turbochannel frequency
446 	 */
447 	switch (pmax_boardtype) {
448 	case DS_3MIN:
449 	case DS_MAXINE:
450 	case DS_3MAXPLUS:
451 	    if (unit == 0) {
452 		asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
453 		bufsiz = 8192;
454 		*((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1;
455 		*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
456 		*((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
457 		asc->dma_start = asic_dma_start;
458 		asc->dma_end = asic_dma_end;
459 		break;
460 	    }
461 	    /*
462 	     * Fall through for turbochannel option.
463 	     */
464 	case DS_3MAX:
465 	default:
466 	    asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);
467 	    asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);
468 	    bufsiz = PER_TGT_DMA_SIZE;
469 	    asc->dma_start = tb_dma_start;
470 	    asc->dma_end = tb_dma_end;
471 	};
472 	/*
473 	 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and
474 	 * maxine are 12.5Mhz.
475 	 */
476 	switch (pmax_boardtype) {
477 	case DS_3MAX:
478 	case DS_3MAXPLUS:
479 		asc->min_period = ASC_MIN_PERIOD25;
480 		asc->max_period = ASC_MAX_PERIOD25;
481 		asc->ccf = ASC_CCF(25);
482 		asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);
483 		asc->tb_ticks = 10;
484 		break;
485 	case DS_3MIN:
486 	case DS_MAXINE:
487 	default:
488 		asc->min_period = ASC_MIN_PERIOD12;
489 		asc->max_period = ASC_MAX_PERIOD12;
490 		asc->ccf = ASC_CCF(13);
491 		asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);
492 		asc->tb_ticks = 20;
493 		break;
494 	};
495 
496 	asc->state = ASC_STATE_IDLE;
497 	asc->target = -1;
498 
499 	regs = asc->regs;
500 
501 	/*
502 	 * Reset chip, fully.  Note that interrupts are already enabled.
503 	 */
504 	s = splbio();
505 
506 	/* preserve our ID for now */
507 	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
508 	asc->myidmask = ~(1 << asc->myid);
509 
510 	asc_reset(asc, regs);
511 
512 	/*
513 	 * Our SCSI id on the bus.
514 	 * The user can set this via the prom on 3maxen/pmaxen.
515 	 * If this changes it is easy to fix: make a default that
516 	 * can be changed as boot arg.
517 	 */
518 #ifdef	unneeded
519 	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
520 			      (scsi_initiator_id[unit] & 0x7);
521 #endif
522 	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
523 	splx(s);
524 
525 	/*
526 	 * Statically partition the DMA buffer between targets.
527 	 * This way we will eventually be able to attach/detach
528 	 * drives on-fly.  And 18k/target is plenty for normal use.
529 	 */
530 
531 	/*
532 	 * Give each target its own DMA buffer region.
533 	 * We may want to try ping ponging buffers later.
534 	 */
535 	for (i = 0; i < ASC_NCMD; i++) {
536 		asc->st[i].dmaBufAddr = asc->buff + bufsiz * i;
537 		asc->st[i].dmaBufSize = bufsiz;
538 	}
539 	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",
540 		unit, cp->pmax_addr, cp->pmax_pri, id);
541 	return (1);
542 }
543 
544 /*
545  * Start activity on a SCSI device.
546  * We maintain information on each device separately since devices can
547  * connect/disconnect during an operation.
548  */
549 void
550 asc_start(scsicmd)
551 	register ScsiCmd *scsicmd;	/* command to start */
552 {
553 	register struct scsi_device *sdp = scsicmd->sd;
554 	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];
555 	int s;
556 
557 	s = splbio();
558 	/*
559 	 * Check if another command is already in progress.
560 	 * We may have to change this if we allow SCSI devices with
561 	 * separate LUNs.
562 	 */
563 	if (asc->cmd[sdp->sd_drive]) {
564 		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,
565 			sdp->sd_driver->d_name);
566 		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,
567 			scsicmd->buflen, 0);
568 		splx(s);
569 	}
570 	asc->cmd[sdp->sd_drive] = scsicmd;
571 	asc_startcmd(asc, sdp->sd_drive);
572 	splx(s);
573 }
574 
575 static void
576 asc_reset(asc, regs)
577 	asc_softc_t asc;
578 	asc_regmap_t *regs;
579 {
580 
581 	/*
582 	 * Reset chip and wait till done
583 	 */
584 	regs->asc_cmd = ASC_CMD_RESET;
585 	MachEmptyWriteBuffer(); DELAY(25);
586 
587 	/* spec says this is needed after reset */
588 	regs->asc_cmd = ASC_CMD_NOP;
589 	MachEmptyWriteBuffer(); DELAY(25);
590 
591 	/*
592 	 * Set up various chip parameters
593 	 */
594 	regs->asc_ccf = asc->ccf;
595 	MachEmptyWriteBuffer(); DELAY(25);
596 	regs->asc_sel_timo = asc->timeout_250;
597 	/* restore our ID */
598 	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;
599 	/* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
600 	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
601 	regs->asc_cnfg3 = 0;
602 	/* zero anything else */
603 	ASC_TC_PUT(regs, 0);
604 	regs->asc_syn_p = asc->min_period;
605 	regs->asc_syn_o = 0;	/* async for now */
606 	MachEmptyWriteBuffer();
607 }
608 
609 /*
610  * Start a SCSI command on a target.
611  */
612 static void
613 asc_startcmd(asc, target)
614 	asc_softc_t asc;
615 	int target;
616 {
617 	register asc_regmap_t *regs;
618 	register ScsiCmd *scsicmd;
619 	register State *state;
620 	int len;
621 
622 	/*
623 	 * See if another target is currently selected on this SCSI bus.
624 	 */
625 	if (asc->target >= 0)
626 		return;
627 
628 	regs = asc->regs;
629 
630 	/*
631 	 * Check to see if a reselection is in progress and if so,
632 	 * try to cancel it or respond to the reselection if it won.
633 	 */
634 	if (asc->state == ASC_STATE_RESEL) {
635 		regs->asc_cmd = ASC_CMD_DISABLE_SEL;
636 		readback(regs->asc_cmd);
637 		while (!(regs->asc_status & ASC_CSR_INT))
638 			DELAY(1);
639 		asc_intr(asc - asc_softc);
640 		/* we will be busy if a reselecting device won */
641 		if (asc->state == ASC_STATE_BUSY)
642 			return;
643 	}
644 
645 	asc->state = ASC_STATE_BUSY;
646 	asc->target = target;
647 
648 	/* cache some pointers */
649 	scsicmd = asc->cmd[target];
650 	state = &asc->st[target];
651 
652 #ifdef DEBUG
653 	if (asc_debug > 1) {
654 		printf("asc_startcmd: %s target %d cmd %x len %d\n",
655 			scsicmd->sd->sd_driver->d_name, target,
656 			scsicmd->cmd[0], scsicmd->buflen);
657 	}
658 	asc_debug_cmd = scsicmd->cmd[0];
659 	if (scsicmd->cmd[0] == SCSI_READ_EXT) {
660 		asc_debug_bn = (scsicmd->cmd[2] << 24) |
661 			(scsicmd->cmd[3] << 16) |
662 			(scsicmd->cmd[4] << 8) |
663 			scsicmd->cmd[5];
664 		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];
665 	}
666 	asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd);
667 	asc_logp->target = asc->target;
668 	asc_logp->state = 0;
669 	asc_logp->msg = 0xff;
670 	if (++asc_logp >= &asc_log[NLOG])
671 		asc_logp = asc_log;
672 #endif
673 
674 	/*
675 	 * Init the chip and target state.
676 	 */
677 	regs->asc_cmd = ASC_CMD_FLUSH;
678 	readback(regs->asc_cmd);
679 	DELAY(2);
680 	state->flags = state->flags & DID_SYNC;
681 	state->error = 0;
682 	state->script = (script_t *)0;
683 	state->msg_out = SCSI_NO_OP;
684 
685 	/*
686 	 * Copy command data to the DMA buffer.
687 	 */
688 	len = scsicmd->cmdlen;
689 	state->dmalen = len;
690 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
691 
692 	/* check for simple SCSI command with no data transfer */
693 	if ((state->buflen = scsicmd->buflen) == 0) {
694 		/* check for sync negotiation */
695 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
696 		    !(state->flags & DID_SYNC)) {
697 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
698 			state->flags |= TRY_SYNC;
699 		} else
700 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
701 		state->buf = (char *)0;
702 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
703 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
704 		state->buf = scsicmd->buf;
705 		state->flags |= DMA_OUT;
706 	} else {
707 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
708 		state->buf = scsicmd->buf;
709 		state->flags |= DMA_IN;
710 	}
711 
712 	/* preload the FIFO with the message to be sent */
713 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
714 	MachEmptyWriteBuffer();
715 
716 	/* start the asc */
717 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
718 	ASC_TC_PUT(regs, len);
719 	readback(regs->asc_cmd);
720 
721 	regs->asc_dbus_id = target;
722 	readback(regs->asc_dbus_id);
723 	regs->asc_syn_p = state->sync_period;
724 	readback(regs->asc_syn_p);
725 	regs->asc_syn_o = state->sync_offset;
726 	readback(regs->asc_syn_o);
727 
728 	if (state->flags & TRY_SYNC)
729 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
730 	else
731 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
732 	readback(regs->asc_cmd);
733 }
734 
735 /*
736  * Interrupt routine
737  *	Take interrupts from the chip
738  *
739  * Implementation:
740  *	Move along the current command's script if
741  *	all is well, invoke error handler if not.
742  */
743 void
744 asc_intr(unit)
745 	int unit;
746 {
747 	register asc_softc_t asc = &asc_softc[unit];
748 	register asc_regmap_t *regs = asc->regs;
749 	register State *state;
750 	register script_t *scpt;
751 	register int ss, ir, status;
752 
753 	/* collect ephemeral information */
754 	status = regs->asc_status;
755 again:
756 	ss = regs->asc_ss;
757 	ir = regs->asc_intr;	/* this resets the previous two */
758 	scpt = asc->script;
759 
760 #ifdef DEBUG
761 	asc_logp->status = PACK(unit, status, ss, ir);
762 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
763 	asc_logp->state = scpt - asc_scripts;
764 	asc_logp->msg = -1;
765 	if (++asc_logp >= &asc_log[NLOG])
766 		asc_logp = asc_log;
767 	if (asc_debug > 2)
768 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
769 			status, ss, ir, scpt - asc_scripts, scpt->condition);
770 #endif
771 
772 	/* check the expected state */
773 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
774 		/*
775 		 * Perform the appropriate operation, then proceed.
776 		 */
777 		if ((*scpt->action)(asc, status, ss, ir)) {
778 			regs->asc_cmd = scpt->command;
779 			readback(regs->asc_cmd);
780 			asc->script = scpt->next;
781 		}
782 		goto done;
783 	}
784 
785 	/* check for message in or out */
786 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
787 		register int len, fifo;
788 
789 		state = &asc->st[asc->target];
790 		switch (ASC_PHASE(status)) {
791 		case ASC_PHASE_DATAI:
792 		case ASC_PHASE_DATAO:
793 			ASC_TC_GET(regs, len);
794 			fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
795 			printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
796 				state->buflen, state->dmalen, len, fifo);
797 			goto abort;
798 
799 		case ASC_PHASE_MSG_IN:
800 			break;
801 
802 		case ASC_PHASE_MSG_OUT:
803 			regs->asc_fifo = state->msg_out;
804 			state->msg_out = SCSI_NO_OP;
805 			regs->asc_cmd = ASC_CMD_XFER_INFO;
806 			readback(regs->asc_cmd);
807 			goto done;
808 
809 		case ASC_PHASE_STATUS:
810 			/* probably an error in the SCSI command */
811 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
812 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
813 			readback(regs->asc_cmd);
814 			goto done;
815 
816 		default:
817 			goto abort;
818 		}
819 
820 		if (state->script)
821 			goto abort;
822 
823 		/* check for DMA in progress */
824 		ASC_TC_GET(regs, len);
825 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
826 		/* flush any data in the FIFO */
827 		if (fifo) {
828 			if (state->flags & DMA_OUT)
829 				len += fifo;
830 			else if (state->flags & DMA_IN) {
831 				u_char *cp;
832 
833 				printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
834 					state->dmalen, len, fifo); /* XXX */
835 				len += fifo;
836 				cp = state->dmaBufAddr + (state->dmalen - len);
837 				while (fifo-- > 0)
838 					*cp++ = regs->asc_fifo;
839 			} else
840 				printf("asc_intr: dmalen %d len %d fifo %d\n",
841 					state->dmalen, len, fifo); /* XXX */
842 			regs->asc_cmd = ASC_CMD_FLUSH;
843 			readback(regs->asc_cmd);
844 			DELAY(2);
845 		}
846 		if (len) {
847 			/* save number of bytes still to be sent or received */
848 			state->dmaresid = len;
849 			/* setup state to resume to */
850 			if (state->flags & DMA_IN)
851 				state->script =
852 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
853 			else if (state->flags & DMA_OUT)
854 				state->script =
855 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
856 			else
857 				state->script = asc->script;
858 		} else {
859 			/* setup state to resume to */
860 			if (state->flags & DMA_IN) {
861 				if (state->flags & DMA_IN_PROGRESS) {
862 					state->flags &= ~DMA_IN_PROGRESS;
863 					(*asc->dma_end)(asc, state, ASCDMA_READ);
864 					len = state->dmalen;
865 					bcopy(state->dmaBufAddr, state->buf,
866 						len);
867 					state->buf += len;
868 					state->buflen -= len;
869 				}
870 				if (state->buflen)
871 					state->script =
872 					    &asc_scripts[SCRIPT_RESUME_IN];
873 				else
874 					state->script =
875 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
876 			} else if (state->flags & DMA_OUT) {
877 				/*
878 				 * If this is the last chunk, the next expected
879 				 * state is to get status.
880 				 */
881 				if (state->flags & DMA_IN_PROGRESS) {
882 					state->flags &= ~DMA_IN_PROGRESS;
883 					(*asc->dma_end)(asc, state, ASCDMA_WRITE);
884 					len = state->dmalen;
885 					state->buf += len;
886 					state->buflen -= len;
887 				}
888 				if (state->buflen)
889 					state->script =
890 					    &asc_scripts[SCRIPT_RESUME_OUT];
891 				else
892 					state->script =
893 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
894 			} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
895 				state->script =
896 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
897 			else
898 				state->script = asc->script;
899 		}
900 
901 		/* setup to receive a message */
902 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
903 		state->msglen = 0;
904 		regs->asc_cmd = ASC_CMD_XFER_INFO;
905 		readback(regs->asc_cmd);
906 		goto done;
907 	}
908 
909 	/* check for SCSI bus reset */
910 	if (ir & ASC_INT_RESET) {
911 		register int i;
912 
913 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
914 		/* need to flush any pending commands */
915 		for (i = 0; i < ASC_NCMD; i++) {
916 			if (!asc->cmd[i])
917 				continue;
918 			asc->st[i].error = EIO;
919 			asc_end(asc, 0, 0, 0);
920 		}
921 		/* rearbitrate synchronous offset */
922 		for (i = 0; i < ASC_NCMD; i++) {
923 			asc->st[i].sync_offset = 0;
924 			asc->st[i].flags = 0;
925 		}
926 		asc->target = -1;
927 		return;
928 	}
929 
930 	/* check for command errors */
931 	if (ir & ASC_INT_ILL)
932 		goto abort;
933 
934 	/* check for disconnect */
935 	if (ir & ASC_INT_DISC) {
936 		state = &asc->st[asc->target];
937 		switch (ASC_SS(ss)) {
938 		case 0: /* device did not respond */
939 			state->error = ENXIO;
940 			asc_end(asc, status, ss, ir);
941 			return;
942 
943 		default:
944 			/*
945 			 * On rare occasions my RZ24 does a disconnect during
946 			 * data in phase and the following seems to keep it
947 			 * happy.
948 			 * XXX Should a scsi disk ever do this??
949 			 */
950 			asc->script = &asc_scripts[SCRIPT_RESEL];
951 			asc->state = ASC_STATE_RESEL;
952 			state->flags |= DISCONN;
953 			regs->asc_cmd = ASC_CMD_ENABLE_SEL;
954 			readback(regs->asc_cmd);
955 			return;
956 		}
957 	}
958 
959 	/* check for reselect */
960 	if (ir & ASC_INT_RESEL) {
961 		unsigned fifo, id, msg;
962 
963 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
964 		if (fifo < 2)
965 			goto abort;
966 		/* read unencoded SCSI ID and convert to binary */
967 		msg = regs->asc_fifo & asc->myidmask;
968 		for (id = 0; (msg & 1) == 0; id++)
969 			msg >>= 1;
970 		/* read identify message */
971 		msg = regs->asc_fifo;
972 #ifdef DEBUG
973 		if (asc_logp == asc_log)
974 			asc_log[NLOG - 1].msg = msg;
975 		else
976 			asc_logp[-1].msg = msg;
977 #endif
978 		if (asc->state != ASC_STATE_RESEL)
979 			goto abort;
980 		asc->state = ASC_STATE_BUSY;
981 		asc->target = id;
982 		state = &asc->st[id];
983 		asc->script = state->script;
984 		state->script = (script_t *)0;
985 		if (!(state->flags & DISCONN))
986 			goto abort;
987 		state->flags &= ~DISCONN;
988 		regs->asc_syn_p = state->sync_period;
989 		regs->asc_syn_o = state->sync_offset;
990 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
991 		readback(regs->asc_cmd);
992 		goto done;
993 	}
994 
995 	/* check if we are being selected as a target */
996 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
997 		goto abort;
998 
999 	/* must be just a ASC_INT_FC */
1000 done:
1001 	MachEmptyWriteBuffer();
1002 	/* watch out for HW race conditions and setup & hold time violations */
1003 	ir = regs->asc_status;
1004 	while (ir != (status = regs->asc_status))
1005 		ir = status;
1006 	if (status & ASC_CSR_INT)
1007 		goto again;
1008 	return;
1009 
1010 abort:
1011 #ifdef DEBUG
1012 	asc_DumpLog("asc_intr");
1013 #endif
1014 #if 0
1015 	panic("asc_intr");
1016 #else
1017 	for (;;);
1018 #endif
1019 }
1020 
1021 /*
1022  * All the many little things that the interrupt
1023  * routine might switch to.
1024  */
1025 
1026 /* ARGSUSED */
1027 static int
1028 script_nop(asc, status, ss, ir)
1029 	register asc_softc_t asc;
1030 	register int status, ss, ir;
1031 {
1032 	return (1);
1033 }
1034 
1035 /* ARGSUSED */
1036 static int
1037 asc_get_status(asc, status, ss, ir)
1038 	register asc_softc_t asc;
1039 	register int status, ss, ir;
1040 {
1041 	register asc_regmap_t *regs = asc->regs;
1042 	register int data;
1043 
1044 	/*
1045 	 * Get the last two bytes in the FIFO.
1046 	 */
1047 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
1048 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
1049 		if (data < 2) {
1050 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
1051 			readback(asc->regs->asc_cmd);
1052 			return (0);
1053 		}
1054 		do {
1055 			data = regs->asc_fifo;
1056 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
1057 	}
1058 
1059 	/* save the status byte */
1060 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
1061 #ifdef DEBUG
1062 	if (asc_logp == asc_log)
1063 		asc_log[NLOG - 1].msg = data;
1064 	else
1065 		asc_logp[-1].msg = data;
1066 #endif
1067 
1068 	/* get the (presumed) command_complete message */
1069 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
1070 		return (1);
1071 
1072 #ifdef DEBUG
1073 	printf("asc_get_status: status %x cmd %x\n",
1074 		asc->st[asc->target].statusByte, data);
1075 	asc_DumpLog("asc_get_status");
1076 #endif
1077 	return (0);
1078 }
1079 
1080 /* ARGSUSED */
1081 static int
1082 asc_end(asc, status, ss, ir)
1083 	register asc_softc_t asc;
1084 	register int status, ss, ir;
1085 {
1086 	register ScsiCmd *scsicmd;
1087 	register State *state;
1088 	register int i, target;
1089 
1090 	asc->state = ASC_STATE_IDLE;
1091 	target = asc->target;
1092 	asc->target = -1;
1093 	scsicmd = asc->cmd[target];
1094 	asc->cmd[target] = (ScsiCmd *)0;
1095 	state = &asc->st[target];
1096 
1097 #ifdef DEBUG
1098 	if (asc_debug > 1) {
1099 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
1100 			scsicmd->sd->sd_driver->d_name, target,
1101 			scsicmd->cmd[0], state->error, state->buflen);
1102 	}
1103 #endif
1104 #ifdef DIAGNOSTIC
1105 	if (target < 0 || !scsicmd)
1106 		panic("asc_end");
1107 #endif
1108 
1109 	/* look for disconnected devices */
1110 	for (i = 0; i < ASC_NCMD; i++) {
1111 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
1112 			continue;
1113 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1114 		readback(asc->regs->asc_cmd);
1115 		asc->state = ASC_STATE_RESEL;
1116 		asc->script = &asc_scripts[SCRIPT_RESEL];
1117 		break;
1118 	}
1119 
1120 	/* look for another device that is ready */
1121 	for (i = 0; i < ASC_NCMD; i++) {
1122 		/* don't restart a disconnected command */
1123 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
1124 			continue;
1125 		asc_startcmd(asc, i);
1126 		break;
1127 	}
1128 
1129 	/* signal device driver that the command is done */
1130 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
1131 		state->buflen, state->statusByte);
1132 
1133 	return (0);
1134 }
1135 
1136 /* ARGSUSED */
1137 static int
1138 asc_dma_in(asc, status, ss, ir)
1139 	register asc_softc_t asc;
1140 	register int status, ss, ir;
1141 {
1142 	register asc_regmap_t *regs = asc->regs;
1143 	register State *state = &asc->st[asc->target];
1144 	register int len;
1145 
1146 	/* check for previous chunk in buffer */
1147 	if (state->flags & DMA_IN_PROGRESS) {
1148 		/*
1149 		 * Only count bytes that have been copied to memory.
1150 		 * There may be some bytes in the FIFO if synchonous transfers
1151 		 * are in progress.
1152 		 */
1153 		(*asc->dma_end)(asc, state, ASCDMA_READ);
1154 		ASC_TC_GET(regs, len);
1155 		len = state->dmalen - len;
1156 		bcopy(state->dmaBufAddr, state->buf, len);
1157 		state->buf += len;
1158 		state->buflen -= len;
1159 	}
1160 
1161 	/* setup to start reading the next chunk */
1162 	len = state->buflen;
1163 	if (len > state->dmaBufSize)
1164 		len = state->dmaBufSize;
1165 	state->dmalen = len;
1166 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
1167 	ASC_TC_PUT(regs, len);
1168 #ifdef DEBUG
1169 	if (asc_debug > 2)
1170 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1171 #endif
1172 
1173 	/* check for next chunk */
1174 	state->flags |= DMA_IN_PROGRESS;
1175 	if (len != state->buflen) {
1176 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1177 		readback(regs->asc_cmd);
1178 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1179 		return (0);
1180 	}
1181 	return (1);
1182 }
1183 
1184 /* ARGSUSED */
1185 static int
1186 asc_last_dma_in(asc, status, ss, ir)
1187 	register asc_softc_t asc;
1188 	register int status, ss, ir;
1189 {
1190 	register asc_regmap_t *regs = asc->regs;
1191 	register State *state = &asc->st[asc->target];
1192 	register int len, fifo;
1193 
1194 	/* copy data from buffer to main memory */
1195 	(*asc->dma_end)(asc, state, ASCDMA_READ);
1196 	ASC_TC_GET(regs, len);
1197 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1198 #ifdef DEBUG
1199 	if (asc_debug > 2)
1200 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1201 			state->buflen, state->dmalen, len, fifo);
1202 #endif
1203 	if (fifo) {
1204 		/* device must be trying to send more than we expect */
1205 		regs->asc_cmd = ASC_CMD_FLUSH;
1206 		readback(regs->asc_cmd);
1207 	}
1208 	state->flags &= ~DMA_IN_PROGRESS;
1209 	len = state->dmalen - len;
1210 	state->buflen -= len;
1211 	bcopy(state->dmaBufAddr, state->buf, len);
1212 
1213 	return (1);
1214 }
1215 
1216 /* ARGSUSED */
1217 static int
1218 asc_resume_in(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 	register int len;
1225 
1226 	/* setup to start reading the next chunk */
1227 	len = state->buflen;
1228 	if (len > state->dmaBufSize)
1229 		len = state->dmaBufSize;
1230 	state->dmalen = len;
1231 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
1232 	ASC_TC_PUT(regs, len);
1233 #ifdef DEBUG
1234 	if (asc_debug > 2)
1235 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1236 			len);
1237 #endif
1238 
1239 	/* check for next chunk */
1240 	state->flags |= DMA_IN_PROGRESS;
1241 	if (len != state->buflen) {
1242 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1243 		readback(regs->asc_cmd);
1244 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1245 		return (0);
1246 	}
1247 	return (1);
1248 }
1249 
1250 /* ARGSUSED */
1251 static int
1252 asc_resume_dma_in(asc, status, ss, ir)
1253 	register asc_softc_t asc;
1254 	register int status, ss, ir;
1255 {
1256 	register asc_regmap_t *regs = asc->regs;
1257 	register State *state = &asc->st[asc->target];
1258 	register int len, off;
1259 
1260 	/* setup to finish reading the current chunk */
1261 	len = state->dmaresid;
1262 	off = state->dmalen - len;
1263 	if ((off & 1) && state->sync_offset) {
1264 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1265 			state->dmalen, len, off); /* XXX */
1266 		regs->asc_res_fifo = state->dmaBufAddr[off];
1267 	}
1268 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
1269 	ASC_TC_PUT(regs, len);
1270 #ifdef DEBUG
1271 	if (asc_debug > 2)
1272 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1273 			state->dmalen, state->buflen, len, off);
1274 #endif
1275 
1276 	/* check for next chunk */
1277 	state->flags |= DMA_IN_PROGRESS;
1278 	if (state->dmalen != state->buflen) {
1279 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1280 		readback(regs->asc_cmd);
1281 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1282 		return (0);
1283 	}
1284 	return (1);
1285 }
1286 
1287 /* ARGSUSED */
1288 static int
1289 asc_dma_out(asc, status, ss, ir)
1290 	register asc_softc_t asc;
1291 	register int status, ss, ir;
1292 {
1293 	register asc_regmap_t *regs = asc->regs;
1294 	register State *state = &asc->st[asc->target];
1295 	register int len, fifo;
1296 
1297 	if (state->flags & DMA_IN_PROGRESS) {
1298 		/* check to be sure previous chunk was finished */
1299 		ASC_TC_GET(regs, len);
1300 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1301 		if (len || fifo)
1302 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1303 				state->buflen, state->dmalen, len, fifo); /* XXX */
1304 		len += fifo;
1305 		len = state->dmalen - len;
1306 		state->buf += len;
1307 		state->buflen -= len;
1308 	}
1309 
1310 	/* setup for this chunck */
1311 	len = state->buflen;
1312 	if (len > state->dmaBufSize)
1313 		len = state->dmaBufSize;
1314 	state->dmalen = len;
1315 	bcopy(state->buf, state->dmaBufAddr, len);
1316 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
1317 	ASC_TC_PUT(regs, len);
1318 #ifdef DEBUG
1319 	if (asc_debug > 2)
1320 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
1321 #endif
1322 
1323 	/* check for next chunk */
1324 	state->flags |= DMA_IN_PROGRESS;
1325 	if (len != state->buflen) {
1326 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1327 		readback(regs->asc_cmd);
1328 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1329 		return (0);
1330 	}
1331 	return (1);
1332 }
1333 
1334 /* ARGSUSED */
1335 static int
1336 asc_last_dma_out(asc, status, ss, ir)
1337 	register asc_softc_t asc;
1338 	register int status, ss, ir;
1339 {
1340 	register asc_regmap_t *regs = asc->regs;
1341 	register State *state = &asc->st[asc->target];
1342 	register int len, fifo;
1343 
1344 	ASC_TC_GET(regs, len);
1345 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1346 #ifdef DEBUG
1347 	if (asc_debug > 2)
1348 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1349 			state->buflen, state->dmalen, len, fifo);
1350 #endif
1351 	if (fifo) {
1352 		len += fifo;
1353 		regs->asc_cmd = ASC_CMD_FLUSH;
1354 		readback(regs->asc_cmd);
1355 	}
1356 	state->flags &= ~DMA_IN_PROGRESS;
1357 	len = state->dmalen - len;
1358 	state->buflen -= len;
1359 	return (1);
1360 }
1361 
1362 /* ARGSUSED */
1363 static int
1364 asc_resume_out(asc, status, ss, ir)
1365 	register asc_softc_t asc;
1366 	register int status, ss, ir;
1367 {
1368 	register asc_regmap_t *regs = asc->regs;
1369 	register State *state = &asc->st[asc->target];
1370 	register int len;
1371 
1372 	/* setup for this chunck */
1373 	len = state->buflen;
1374 	if (len > state->dmaBufSize)
1375 		len = state->dmaBufSize;
1376 	state->dmalen = len;
1377 	bcopy(state->buf, state->dmaBufAddr, len);
1378 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
1379 	ASC_TC_PUT(regs, len);
1380 #ifdef DEBUG
1381 	if (asc_debug > 2)
1382 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1383 			len);
1384 #endif
1385 
1386 	/* check for next chunk */
1387 	state->flags |= DMA_IN_PROGRESS;
1388 	if (len != state->buflen) {
1389 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1390 		readback(regs->asc_cmd);
1391 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1392 		return (0);
1393 	}
1394 	return (1);
1395 }
1396 
1397 /* ARGSUSED */
1398 static int
1399 asc_resume_dma_out(asc, status, ss, ir)
1400 	register asc_softc_t asc;
1401 	register int status, ss, ir;
1402 {
1403 	register asc_regmap_t *regs = asc->regs;
1404 	register State *state = &asc->st[asc->target];
1405 	register int len, off;
1406 
1407 	/* setup to finish writing this chunk */
1408 	len = state->dmaresid;
1409 	off = state->dmalen - len;
1410 	if (off & 1) {
1411 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1412 			state->dmalen, len, off); /* XXX */
1413 		regs->asc_fifo = state->dmaBufAddr[off];
1414 		off++;
1415 		len--;
1416 	}
1417 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
1418 	ASC_TC_PUT(regs, len);
1419 #ifdef DEBUG
1420 	if (asc_debug > 2)
1421 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1422 			state->dmalen, state->buflen, len, off);
1423 #endif
1424 
1425 	/* check for next chunk */
1426 	state->flags |= DMA_IN_PROGRESS;
1427 	if (state->dmalen != state->buflen) {
1428 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1429 		readback(regs->asc_cmd);
1430 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1431 		return (0);
1432 	}
1433 	return (1);
1434 }
1435 
1436 /* ARGSUSED */
1437 static int
1438 asc_sendsync(asc, status, ss, ir)
1439 	register asc_softc_t asc;
1440 	register int status, ss, ir;
1441 {
1442 	register asc_regmap_t *regs = asc->regs;
1443 	register State *state = &asc->st[asc->target];
1444 
1445 	/* send the extended synchronous negotiation message */
1446 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1447 	MachEmptyWriteBuffer();
1448 	regs->asc_fifo = 3;
1449 	MachEmptyWriteBuffer();
1450 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1451 	MachEmptyWriteBuffer();
1452 	regs->asc_fifo = SCSI_MIN_PERIOD;
1453 	MachEmptyWriteBuffer();
1454 	regs->asc_fifo = ASC_MAX_OFFSET;
1455 	/* state to resume after we see the sync reply message */
1456 	state->script = asc->script + 2;
1457 	state->msglen = 0;
1458 	return (1);
1459 }
1460 
1461 /* ARGSUSED */
1462 static int
1463 asc_replysync(asc, status, ss, ir)
1464 	register asc_softc_t asc;
1465 	register int status, ss, ir;
1466 {
1467 	register asc_regmap_t *regs = asc->regs;
1468 	register State *state = &asc->st[asc->target];
1469 
1470 #ifdef DEBUG
1471 	if (asc_debug > 2)
1472 		printf("asc_replysync: %x %x\n",
1473 			asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
1474 			state->sync_offset);
1475 #endif
1476 	/* send synchronous transfer in response to a request */
1477 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1478 	MachEmptyWriteBuffer();
1479 	regs->asc_fifo = 3;
1480 	MachEmptyWriteBuffer();
1481 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1482 	MachEmptyWriteBuffer();
1483 	regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
1484 	MachEmptyWriteBuffer();
1485 	regs->asc_fifo = state->sync_offset;
1486 	regs->asc_cmd = ASC_CMD_XFER_INFO;
1487 	readback(regs->asc_cmd);
1488 
1489 	/* return to the appropriate script */
1490 	if (!state->script) {
1491 #ifdef DEBUG
1492 		asc_DumpLog("asc_replsync");
1493 #endif
1494 		panic("asc_replysync");
1495 	}
1496 	asc->script = state->script;
1497 	state->script = (script_t *)0;
1498 	return (0);
1499 }
1500 
1501 /* ARGSUSED */
1502 static int
1503 asc_msg_in(asc, status, ss, ir)
1504 	register asc_softc_t asc;
1505 	register int status, ss, ir;
1506 {
1507 	register asc_regmap_t *regs = asc->regs;
1508 	register State *state = &asc->st[asc->target];
1509 	register int msg;
1510 	int i;
1511 
1512 	/* read one message byte */
1513 	msg = regs->asc_fifo;
1514 #ifdef DEBUG
1515 	if (asc_logp == asc_log)
1516 		asc_log[NLOG - 1].msg = msg;
1517 	else
1518 		asc_logp[-1].msg = msg;
1519 #endif
1520 
1521 	/* check for multi-byte message */
1522 	if (state->msglen != 0) {
1523 		/* first byte is the message length */
1524 		if (state->msglen < 0) {
1525 			state->msglen = msg;
1526 			return (1);
1527 		}
1528 		if (state->msgcnt >= state->msglen)
1529 			goto abort;
1530 		state->msg_in[state->msgcnt++] = msg;
1531 
1532 		/* did we just read the last byte of the message? */
1533 		if (state->msgcnt != state->msglen)
1534 			return (1);
1535 
1536 		/* process an extended message */
1537 #ifdef DEBUG
1538 		if (asc_debug > 2)
1539 			printf("asc_msg_in: msg %x %x %x\n",
1540 				state->msg_in[0],
1541 				state->msg_in[1],
1542 				state->msg_in[2]);
1543 #endif
1544 		switch (state->msg_in[0]) {
1545 		case SCSI_SYNCHRONOUS_XFER:
1546 			state->flags |= DID_SYNC;
1547 			state->sync_offset = state->msg_in[2];
1548 
1549 			/* convert SCSI period to ASC period */
1550 			i = state->msg_in[1] / asc->tb_ticks;
1551 			if (i < asc->min_period)
1552 				i = asc->min_period;
1553 			else if (i >= asc->max_period) {
1554 				/* can't do sync transfer, period too long */
1555 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
1556 					asc - asc_softc, asc->target, i);
1557 				i = asc->max_period;
1558 				state->sync_offset = 0;
1559 			}
1560 			if ((i * asc->tb_ticks) != state->msg_in[1])
1561 				i++;
1562 			state->sync_period = i & 0x1F;
1563 
1564 			/*
1565 			 * If this is a request, check minimums and
1566 			 * send back an acknowledge.
1567 			 */
1568 			if (!(state->flags & TRY_SYNC)) {
1569 				regs->asc_cmd = ASC_CMD_SET_ATN;
1570 				readback(regs->asc_cmd);
1571 
1572 				if (state->sync_period < asc->min_period)
1573 					state->sync_period =
1574 						asc->min_period;
1575 				if (state->sync_offset > ASC_MAX_OFFSET)
1576 					state->sync_offset =
1577 						ASC_MAX_OFFSET;
1578 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1579 				regs->asc_syn_p = state->sync_period;
1580 				readback(regs->asc_syn_p);
1581 				regs->asc_syn_o = state->sync_offset;
1582 				readback(regs->asc_syn_o);
1583 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
1584 				readback(regs->asc_cmd);
1585 				return (0);
1586 			}
1587 
1588 			regs->asc_syn_p = state->sync_period;
1589 			readback(regs->asc_syn_p);
1590 			regs->asc_syn_o = state->sync_offset;
1591 			readback(regs->asc_syn_o);
1592 			goto done;
1593 
1594 		default:
1595 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
1596 				asc - asc_softc, asc->target,
1597 				state->msg_in[0]);
1598 			goto reject;
1599 		}
1600 	}
1601 
1602 	/* process first byte of a message */
1603 #ifdef DEBUG
1604 	if (asc_debug > 2)
1605 		printf("asc_msg_in: msg %x\n", msg);
1606 #endif
1607 	switch (msg) {
1608 #if 0
1609 	case SCSI_MESSAGE_REJECT:
1610 		printf(" did not like SYNCH xfer "); /* XXX */
1611 		state->flags |= DID_SYNC;
1612 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1613 		readback(regs->asc_cmd);
1614 		status = asc_wait(regs, ASC_CSR_INT);
1615 		ir = regs->asc_intr;
1616 		/* some just break out here, some dont */
1617 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1618 			regs->asc_fifo = SCSI_ABORT;
1619 			regs->asc_cmd = ASC_CMD_XFER_INFO;
1620 			readback(regs->asc_cmd);
1621 			status = asc_wait(regs, ASC_CSR_INT);
1622 			ir = regs->asc_intr;
1623 		}
1624 		if (ir & ASC_INT_DISC) {
1625 			asc_end(asc, status, 0, ir);
1626 			return (0);
1627 		}
1628 		goto status;
1629 #endif
1630 
1631 	case SCSI_EXTENDED_MSG: /* read an extended message */
1632 		/* setup to read message length next */
1633 		state->msglen = -1;
1634 		state->msgcnt = 0;
1635 		return (1);
1636 
1637 	case SCSI_NO_OP:
1638 		break;
1639 
1640 	case SCSI_SAVE_DATA_POINTER:
1641 		/* expect another message */
1642 		return (1);
1643 
1644 	case SCSI_RESTORE_POINTERS:
1645 		/*
1646 		 * Need to do the following if resuming synchonous data in
1647 		 * on an odd byte boundary.
1648 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1649 		 */
1650 		break;
1651 
1652 	case SCSI_DISCONNECT:
1653 		if (state->flags & DISCONN)
1654 			goto abort;
1655 		state->flags |= DISCONN;
1656 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1657 		readback(regs->asc_cmd);
1658 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1659 		return (0);
1660 
1661 	default:
1662 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
1663 			asc - asc_softc, asc->target, msg);
1664 	reject:
1665 		/* request a message out before acknowledging this message */
1666 		state->msg_out = SCSI_MESSAGE_REJECT;
1667 		regs->asc_cmd = ASC_CMD_SET_ATN;
1668 		readback(regs->asc_cmd);
1669 	}
1670 
1671 done:
1672 	/* return to original script */
1673 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
1674 	readback(regs->asc_cmd);
1675 	if (!state->script) {
1676 	abort:
1677 #ifdef DEBUG
1678 		asc_DumpLog("asc_msg_in");
1679 #endif
1680 		panic("asc_msg_in");
1681 	}
1682 	asc->script = state->script;
1683 	state->script = (script_t *)0;
1684 	return (0);
1685 }
1686 
1687 /* ARGSUSED */
1688 static int
1689 asc_disconnect(asc, status, ss, ir)
1690 	register asc_softc_t asc;
1691 	register int status, ss, ir;
1692 {
1693 	register State *state = &asc->st[asc->target];
1694 
1695 	asc->target = -1;
1696 	asc->state = ASC_STATE_RESEL;
1697 	return (1);
1698 }
1699 
1700 /*
1701  * DMA handling routines. For a turbochannel device, just set the dmar
1702  * for the I/O ASIC, handle the actual DMA interface.
1703  */
1704 static void
1705 tb_dma_start(asc, state, cp, flag)
1706 	asc_softc_t asc;
1707 	State *state;
1708 	caddr_t cp;
1709 	int flag;
1710 {
1711 
1712 	if (flag == ASCDMA_WRITE)
1713 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
1714 	else
1715 		*asc->dmar = ASC_DMA_ADDR(cp);
1716 }
1717 
1718 static void
1719 tb_dma_end(asc, state, flag)
1720 	asc_softc_t asc;
1721 	State *state;
1722 	int flag;
1723 {
1724 
1725 }
1726 
1727 static void
1728 asic_dma_start(asc, state, cp, flag)
1729 	asc_softc_t asc;
1730 	State *state;
1731 	caddr_t cp;
1732 	int flag;
1733 {
1734 	register volatile u_int *ssr = (volatile u_int *)
1735 		ASIC_REG_CSR(asic_base);
1736 	u_int phys, nphys;
1737 
1738 	/* stop DMA engine first */
1739 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1740 	* ((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
1741 
1742 	phys = MACH_CACHED_TO_PHYS(cp);
1743 	cp = (caddr_t)pmax_trunc_page(cp + NBPG);
1744 	nphys = MACH_CACHED_TO_PHYS(cp);
1745 
1746 	asc->dma_next = cp;
1747 	asc->dma_xfer = state->dmalen - (nphys - phys);
1748 
1749 	*(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) =
1750 		ASIC_DMA_ADDR(phys);
1751 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
1752 		ASIC_DMA_ADDR(nphys);
1753 	if (flag == ASCDMA_READ)
1754 		*ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI;
1755 	else
1756 		*ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI;
1757 	MachEmptyWriteBuffer();
1758 }
1759 
1760 static void
1761 asic_dma_end(asc, state, flag)
1762 	asc_softc_t asc;
1763 	State *state;
1764 	int flag;
1765 {
1766 	register volatile u_int *ssr = (volatile u_int *)
1767 		ASIC_REG_CSR(asic_base);
1768 	int nb;
1769 
1770 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1771 	*((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1;
1772 	*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
1773 	MachEmptyWriteBuffer();
1774 
1775 	if (flag == ASCDMA_READ) {
1776 		MachFlushDCache(MACH_PHYS_TO_CACHED(
1777 		    MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
1778 		if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) {
1779 			/* pick up last upto6 bytes, sigh. */
1780 			register u_short *to;
1781 			register int w;
1782 
1783 			/* Last byte really xferred is.. */
1784 			to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1));
1785 			w = *(int *)ASIC_REG_SCSI_SDR0(asic_base);
1786 			*to++ = w;
1787 			if (--nb > 0) {
1788 				w >>= 16;
1789 				*to++ = w;
1790 			}
1791 			if (--nb > 0) {
1792 				w = *(int *)ASIC_REG_SCSI_SDR1(asic_base);
1793 				*to++ = w;
1794 			}
1795 		}
1796 	}
1797 }
1798 
1799 #ifdef notdef
1800 /*
1801  * Called by asic_intr() for scsi dma pointer update interrupts.
1802  */
1803 void
1804 asc_dma_intr()
1805 {
1806 	asc_softc_t asc = &asc_softc[0];
1807 	u_int next_phys;
1808 
1809 	asc->dma_xfer -= NBPG;
1810 	if (asc->dma_xfer <= -NBPG) {
1811 		volatile u_int *ssr = (volatile u_int *)
1812 			ASIC_REG_CSR(asic_base);
1813 		*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1814 	} else {
1815 		asc->dma_next += NBPG;
1816 		next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
1817 	}
1818 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
1819 		ASIC_DMA_ADDR(next_phys);
1820 	MachEmptyWriteBuffer();
1821 }
1822 #endif
1823 
1824 #ifdef DEBUG
1825 asc_DumpLog(str)
1826 	char *str;
1827 {
1828 	register struct asc_log *lp;
1829 	register u_int status;
1830 
1831 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
1832 		asc_debug_bn, asc_debug_sz);
1833 	lp = asc_logp;
1834 	do {
1835 		status = lp->status;
1836 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
1837 			status >> 24,
1838 			lp->target,
1839 			(status >> 16) & 0xFF,
1840 			(status >> 8) & 0xFF,
1841 			status & 0XFF,
1842 			lp->state,
1843 			asc_scripts[lp->state].condition,
1844 			lp->msg);
1845 		if (++lp >= &asc_log[NLOG])
1846 			lp = asc_log;
1847 	} while (lp != asc_logp);
1848 }
1849 #endif
1850 
1851 #endif	/* NASC > 0 */
1852