xref: /original-bsd/sys/pmax/dev/asc.c (revision cf2124ff)
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.9 (Berkeley) 12/20/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 <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 chuck 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 chuck 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 			MachEmptyWriteBuffer();
845 			DELAY(2);
846 		}
847 		if (len) {
848 			/* save number of bytes still to be sent or received */
849 			state->dmaresid = len;
850 			/* setup state to resume to */
851 			if (state->flags & DMA_IN)
852 				state->script =
853 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
854 			else if (state->flags & DMA_OUT)
855 				state->script =
856 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
857 			else
858 				state->script = asc->script;
859 		} else {
860 			/* setup state to resume to */
861 			if (state->flags & DMA_IN) {
862 				if (state->flags & DMA_IN_PROGRESS) {
863 					state->flags &= ~DMA_IN_PROGRESS;
864 					(*asc->dma_end)(asc, state, ASCDMA_READ);
865 					len = state->dmalen;
866 					bcopy(state->dmaBufAddr, state->buf,
867 						len);
868 					state->buf += len;
869 					state->buflen -= len;
870 				}
871 				if (state->buflen)
872 					state->script =
873 					    &asc_scripts[SCRIPT_RESUME_IN];
874 				else
875 					state->script =
876 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
877 			} else if (state->flags & DMA_OUT) {
878 				/*
879 				 * If this is the last chunk, the next expected
880 				 * state is to get status.
881 				 */
882 				if (state->flags & DMA_IN_PROGRESS) {
883 					state->flags &= ~DMA_IN_PROGRESS;
884 					(*asc->dma_end)(asc, state, ASCDMA_WRITE);
885 					len = state->dmalen;
886 					state->buf += len;
887 					state->buflen -= len;
888 				}
889 				if (state->buflen)
890 					state->script =
891 					    &asc_scripts[SCRIPT_RESUME_OUT];
892 				else
893 					state->script =
894 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
895 			} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
896 				state->script =
897 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
898 			else
899 				state->script = asc->script;
900 		}
901 
902 		/* setup to receive a message */
903 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
904 		state->msglen = 0;
905 		regs->asc_cmd = ASC_CMD_XFER_INFO;
906 		readback(regs->asc_cmd);
907 		goto done;
908 	}
909 
910 	/* check for SCSI bus reset */
911 	if (ir & ASC_INT_RESET) {
912 		register int i;
913 
914 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
915 		/* need to flush any pending commands */
916 		for (i = 0; i < ASC_NCMD; i++) {
917 			if (!asc->cmd[i])
918 				continue;
919 			asc->st[i].error = EIO;
920 			asc_end(asc, 0, 0, 0);
921 		}
922 		/* rearbitrate synchronous offset */
923 		for (i = 0; i < ASC_NCMD; i++) {
924 			asc->st[i].sync_offset = 0;
925 			asc->st[i].flags = 0;
926 		}
927 		asc->target = -1;
928 		return;
929 	}
930 
931 	/* check for command errors */
932 	if (ir & ASC_INT_ILL)
933 		goto abort;
934 
935 	/* check for disconnect */
936 	if (ir & ASC_INT_DISC) {
937 		state = &asc->st[asc->target];
938 		switch (ASC_SS(ss)) {
939 		case 0: /* device did not respond */
940 			state->error = ENXIO;
941 			asc_end(asc, status, ss, ir);
942 			return;
943 
944 		default:
945 			/*
946 			 * On rare occasions my RZ24 does a disconnect during
947 			 * data in phase and the following seems to keep it
948 			 * happy.
949 			 * XXX Should a scsi disk ever do this??
950 			 */
951 			asc->script = &asc_scripts[SCRIPT_RESEL];
952 			asc->state = ASC_STATE_RESEL;
953 			state->flags |= DISCONN;
954 			regs->asc_cmd = ASC_CMD_ENABLE_SEL;
955 			readback(regs->asc_cmd);
956 			return;
957 		}
958 	}
959 
960 	/* check for reselect */
961 	if (ir & ASC_INT_RESEL) {
962 		unsigned fifo, id, msg;
963 
964 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
965 		if (fifo < 2)
966 			goto abort;
967 		/* read unencoded SCSI ID and convert to binary */
968 		msg = regs->asc_fifo & asc->myidmask;
969 		for (id = 0; (msg & 1) == 0; id++)
970 			msg >>= 1;
971 		/* read identify message */
972 		msg = regs->asc_fifo;
973 #ifdef DEBUG
974 		if (asc_logp == asc_log)
975 			asc_log[NLOG - 1].msg = msg;
976 		else
977 			asc_logp[-1].msg = msg;
978 #endif
979 		if (asc->state != ASC_STATE_RESEL)
980 			goto abort;
981 		asc->state = ASC_STATE_BUSY;
982 		asc->target = id;
983 		state = &asc->st[id];
984 		asc->script = state->script;
985 		state->script = (script_t *)0;
986 		if (!(state->flags & DISCONN))
987 			goto abort;
988 		state->flags &= ~DISCONN;
989 		regs->asc_syn_p = state->sync_period;
990 		regs->asc_syn_o = state->sync_offset;
991 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
992 		readback(regs->asc_cmd);
993 		goto done;
994 	}
995 
996 	/* check if we are being selected as a target */
997 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
998 		goto abort;
999 
1000 	/* must be just a ASC_INT_FC */
1001 done:
1002 	MachEmptyWriteBuffer();
1003 	/* watch out for HW race conditions and setup & hold time violations */
1004 	ir = regs->asc_status;
1005 	while (ir != (status = regs->asc_status))
1006 		ir = status;
1007 	if (status & ASC_CSR_INT)
1008 		goto again;
1009 	return;
1010 
1011 abort:
1012 #ifdef DEBUG
1013 	asc_DumpLog("asc_intr");
1014 #endif
1015 #if 0
1016 	panic("asc_intr");
1017 #else
1018 	for (;;);
1019 #endif
1020 }
1021 
1022 /*
1023  * All the many little things that the interrupt
1024  * routine might switch to.
1025  */
1026 
1027 /* ARGSUSED */
1028 static int
1029 script_nop(asc, status, ss, ir)
1030 	register asc_softc_t asc;
1031 	register int status, ss, ir;
1032 {
1033 	return (1);
1034 }
1035 
1036 /* ARGSUSED */
1037 static int
1038 asc_get_status(asc, status, ss, ir)
1039 	register asc_softc_t asc;
1040 	register int status, ss, ir;
1041 {
1042 	register asc_regmap_t *regs = asc->regs;
1043 	register int data;
1044 
1045 	/*
1046 	 * Get the last two bytes in the FIFO.
1047 	 */
1048 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
1049 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
1050 		if (data < 2) {
1051 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
1052 			readback(asc->regs->asc_cmd);
1053 			return (0);
1054 		}
1055 		do {
1056 			data = regs->asc_fifo;
1057 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
1058 	}
1059 
1060 	/* save the status byte */
1061 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
1062 #ifdef DEBUG
1063 	if (asc_logp == asc_log)
1064 		asc_log[NLOG - 1].msg = data;
1065 	else
1066 		asc_logp[-1].msg = data;
1067 #endif
1068 
1069 	/* get the (presumed) command_complete message */
1070 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
1071 		return (1);
1072 
1073 #ifdef DEBUG
1074 	printf("asc_get_status: status %x cmd %x\n",
1075 		asc->st[asc->target].statusByte, data);
1076 	asc_DumpLog("asc_get_status");
1077 #endif
1078 	return (0);
1079 }
1080 
1081 /* ARGSUSED */
1082 static int
1083 asc_end(asc, status, ss, ir)
1084 	register asc_softc_t asc;
1085 	register int status, ss, ir;
1086 {
1087 	register ScsiCmd *scsicmd;
1088 	register State *state;
1089 	register int i, target;
1090 
1091 	asc->state = ASC_STATE_IDLE;
1092 	target = asc->target;
1093 	asc->target = -1;
1094 	scsicmd = asc->cmd[target];
1095 	asc->cmd[target] = (ScsiCmd *)0;
1096 	state = &asc->st[target];
1097 
1098 #ifdef DEBUG
1099 	if (asc_debug > 1) {
1100 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
1101 			scsicmd->sd->sd_driver->d_name, target,
1102 			scsicmd->cmd[0], state->error, state->buflen);
1103 	}
1104 #endif
1105 #ifdef DIAGNOSTIC
1106 	if (target < 0 || !scsicmd)
1107 		panic("asc_end");
1108 #endif
1109 
1110 	/* look for disconnected devices */
1111 	for (i = 0; i < ASC_NCMD; i++) {
1112 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
1113 			continue;
1114 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1115 		readback(asc->regs->asc_cmd);
1116 		asc->state = ASC_STATE_RESEL;
1117 		asc->script = &asc_scripts[SCRIPT_RESEL];
1118 		break;
1119 	}
1120 
1121 	/* look for another device that is ready */
1122 	for (i = 0; i < ASC_NCMD; i++) {
1123 		/* don't restart a disconnected command */
1124 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
1125 			continue;
1126 		asc_startcmd(asc, i);
1127 		break;
1128 	}
1129 
1130 	/* signal device driver that the command is done */
1131 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
1132 		state->buflen, state->statusByte);
1133 
1134 	return (0);
1135 }
1136 
1137 /* ARGSUSED */
1138 static int
1139 asc_dma_in(asc, status, ss, ir)
1140 	register asc_softc_t asc;
1141 	register int status, ss, ir;
1142 {
1143 	register asc_regmap_t *regs = asc->regs;
1144 	register State *state = &asc->st[asc->target];
1145 	register int len;
1146 
1147 	/* check for previous chunk in buffer */
1148 	if (state->flags & DMA_IN_PROGRESS) {
1149 		/*
1150 		 * Only count bytes that have been copied to memory.
1151 		 * There may be some bytes in the FIFO if synchonous transfers
1152 		 * are in progress.
1153 		 */
1154 		(*asc->dma_end)(asc, state, ASCDMA_READ);
1155 		ASC_TC_GET(regs, len);
1156 		len = state->dmalen - len;
1157 		bcopy(state->dmaBufAddr, state->buf, len);
1158 		state->buf += len;
1159 		state->buflen -= len;
1160 	}
1161 
1162 	/* setup to start reading the next chunk */
1163 	len = state->buflen;
1164 	if (len > state->dmaBufSize)
1165 		len = state->dmaBufSize;
1166 	state->dmalen = len;
1167 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
1168 	ASC_TC_PUT(regs, len);
1169 #ifdef DEBUG
1170 	if (asc_debug > 2)
1171 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1172 #endif
1173 
1174 	/* check for next chunk */
1175 	state->flags |= DMA_IN_PROGRESS;
1176 	if (len != state->buflen) {
1177 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1178 		readback(regs->asc_cmd);
1179 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1180 		return (0);
1181 	}
1182 	return (1);
1183 }
1184 
1185 /* ARGSUSED */
1186 static int
1187 asc_last_dma_in(asc, status, ss, ir)
1188 	register asc_softc_t asc;
1189 	register int status, ss, ir;
1190 {
1191 	register asc_regmap_t *regs = asc->regs;
1192 	register State *state = &asc->st[asc->target];
1193 	register int len, fifo;
1194 
1195 	/* copy data from buffer to main memory */
1196 	(*asc->dma_end)(asc, state, ASCDMA_READ);
1197 	ASC_TC_GET(regs, len);
1198 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1199 #ifdef DEBUG
1200 	if (asc_debug > 2)
1201 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1202 			state->buflen, state->dmalen, len, fifo);
1203 #endif
1204 	if (fifo) {
1205 		/* device must be trying to send more than we expect */
1206 		regs->asc_cmd = ASC_CMD_FLUSH;
1207 		readback(regs->asc_cmd);
1208 		MachEmptyWriteBuffer();
1209 	}
1210 	state->flags &= ~DMA_IN_PROGRESS;
1211 	len = state->dmalen - len;
1212 	state->buflen -= len;
1213 	bcopy(state->dmaBufAddr, state->buf, len);
1214 
1215 	return (1);
1216 }
1217 
1218 /* ARGSUSED */
1219 static int
1220 asc_resume_in(asc, status, ss, ir)
1221 	register asc_softc_t asc;
1222 	register int status, ss, ir;
1223 {
1224 	register asc_regmap_t *regs = asc->regs;
1225 	register State *state = &asc->st[asc->target];
1226 	register int len;
1227 
1228 	/* setup to start reading the next chunk */
1229 	len = state->buflen;
1230 	if (len > state->dmaBufSize)
1231 		len = state->dmaBufSize;
1232 	state->dmalen = len;
1233 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);
1234 	ASC_TC_PUT(regs, len);
1235 #ifdef DEBUG
1236 	if (asc_debug > 2)
1237 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1238 			len);
1239 #endif
1240 
1241 	/* check for next chunk */
1242 	state->flags |= DMA_IN_PROGRESS;
1243 	if (len != state->buflen) {
1244 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1245 		readback(regs->asc_cmd);
1246 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1247 		return (0);
1248 	}
1249 	return (1);
1250 }
1251 
1252 /* ARGSUSED */
1253 static int
1254 asc_resume_dma_in(asc, status, ss, ir)
1255 	register asc_softc_t asc;
1256 	register int status, ss, ir;
1257 {
1258 	register asc_regmap_t *regs = asc->regs;
1259 	register State *state = &asc->st[asc->target];
1260 	register int len, off;
1261 
1262 	/* setup to finish reading the current chunk */
1263 	len = state->dmaresid;
1264 	off = state->dmalen - len;
1265 	if ((off & 1) && state->sync_offset) {
1266 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1267 			state->dmalen, len, off); /* XXX */
1268 		regs->asc_res_fifo = state->dmaBufAddr[off];
1269 	}
1270 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);
1271 	ASC_TC_PUT(regs, len);
1272 #ifdef DEBUG
1273 	if (asc_debug > 2)
1274 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1275 			state->dmalen, state->buflen, len, off);
1276 #endif
1277 
1278 	/* check for next chunk */
1279 	state->flags |= DMA_IN_PROGRESS;
1280 	if (state->dmalen != state->buflen) {
1281 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1282 		readback(regs->asc_cmd);
1283 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1284 		return (0);
1285 	}
1286 	return (1);
1287 }
1288 
1289 /* ARGSUSED */
1290 static int
1291 asc_dma_out(asc, status, ss, ir)
1292 	register asc_softc_t asc;
1293 	register int status, ss, ir;
1294 {
1295 	register asc_regmap_t *regs = asc->regs;
1296 	register State *state = &asc->st[asc->target];
1297 	register int len, fifo;
1298 
1299 	if (state->flags & DMA_IN_PROGRESS) {
1300 		/* check to be sure previous chunk was finished */
1301 		ASC_TC_GET(regs, len);
1302 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1303 		if (len || fifo)
1304 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1305 				state->buflen, state->dmalen, len, fifo); /* XXX */
1306 		len += fifo;
1307 		len = state->dmalen - len;
1308 		state->buf += len;
1309 		state->buflen -= len;
1310 	}
1311 
1312 	/* setup for this chunck */
1313 	len = state->buflen;
1314 	if (len > state->dmaBufSize)
1315 		len = state->dmaBufSize;
1316 	state->dmalen = len;
1317 	bcopy(state->buf, state->dmaBufAddr, len);
1318 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
1319 	ASC_TC_PUT(regs, len);
1320 #ifdef DEBUG
1321 	if (asc_debug > 2)
1322 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
1323 #endif
1324 
1325 	/* check for next chunk */
1326 	state->flags |= DMA_IN_PROGRESS;
1327 	if (len != state->buflen) {
1328 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1329 		readback(regs->asc_cmd);
1330 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1331 		return (0);
1332 	}
1333 	return (1);
1334 }
1335 
1336 /* ARGSUSED */
1337 static int
1338 asc_last_dma_out(asc, status, ss, ir)
1339 	register asc_softc_t asc;
1340 	register int status, ss, ir;
1341 {
1342 	register asc_regmap_t *regs = asc->regs;
1343 	register State *state = &asc->st[asc->target];
1344 	register int len, fifo;
1345 
1346 	ASC_TC_GET(regs, len);
1347 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1348 #ifdef DEBUG
1349 	if (asc_debug > 2)
1350 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1351 			state->buflen, state->dmalen, len, fifo);
1352 #endif
1353 	if (fifo) {
1354 		len += fifo;
1355 		regs->asc_cmd = ASC_CMD_FLUSH;
1356 		readback(regs->asc_cmd);
1357 		MachEmptyWriteBuffer();
1358 	}
1359 	state->flags &= ~DMA_IN_PROGRESS;
1360 	len = state->dmalen - len;
1361 	state->buflen -= len;
1362 	return (1);
1363 }
1364 
1365 /* ARGSUSED */
1366 static int
1367 asc_resume_out(asc, status, ss, ir)
1368 	register asc_softc_t asc;
1369 	register int status, ss, ir;
1370 {
1371 	register asc_regmap_t *regs = asc->regs;
1372 	register State *state = &asc->st[asc->target];
1373 	register int len;
1374 
1375 	/* setup for this chunck */
1376 	len = state->buflen;
1377 	if (len > state->dmaBufSize)
1378 		len = state->dmaBufSize;
1379 	state->dmalen = len;
1380 	bcopy(state->buf, state->dmaBufAddr, len);
1381 	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
1382 	ASC_TC_PUT(regs, len);
1383 #ifdef DEBUG
1384 	if (asc_debug > 2)
1385 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1386 			len);
1387 #endif
1388 
1389 	/* check for next chunk */
1390 	state->flags |= DMA_IN_PROGRESS;
1391 	if (len != state->buflen) {
1392 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1393 		readback(regs->asc_cmd);
1394 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1395 		return (0);
1396 	}
1397 	return (1);
1398 }
1399 
1400 /* ARGSUSED */
1401 static int
1402 asc_resume_dma_out(asc, status, ss, ir)
1403 	register asc_softc_t asc;
1404 	register int status, ss, ir;
1405 {
1406 	register asc_regmap_t *regs = asc->regs;
1407 	register State *state = &asc->st[asc->target];
1408 	register int len, off;
1409 
1410 	/* setup to finish writing this chunk */
1411 	len = state->dmaresid;
1412 	off = state->dmalen - len;
1413 	if (off & 1) {
1414 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1415 			state->dmalen, len, off); /* XXX */
1416 		regs->asc_fifo = state->dmaBufAddr[off];
1417 		off++;
1418 		len--;
1419 	}
1420 	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE);
1421 	ASC_TC_PUT(regs, len);
1422 #ifdef DEBUG
1423 	if (asc_debug > 2)
1424 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1425 			state->dmalen, state->buflen, len, off);
1426 #endif
1427 
1428 	/* check for next chunk */
1429 	state->flags |= DMA_IN_PROGRESS;
1430 	if (state->dmalen != state->buflen) {
1431 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1432 		readback(regs->asc_cmd);
1433 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1434 		return (0);
1435 	}
1436 	return (1);
1437 }
1438 
1439 /* ARGSUSED */
1440 static int
1441 asc_sendsync(asc, status, ss, ir)
1442 	register asc_softc_t asc;
1443 	register int status, ss, ir;
1444 {
1445 	register asc_regmap_t *regs = asc->regs;
1446 	register State *state = &asc->st[asc->target];
1447 
1448 	/* send the extended synchronous negotiation message */
1449 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1450 	MachEmptyWriteBuffer();
1451 	regs->asc_fifo = 3;
1452 	MachEmptyWriteBuffer();
1453 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1454 	MachEmptyWriteBuffer();
1455 	regs->asc_fifo = SCSI_MIN_PERIOD;
1456 	MachEmptyWriteBuffer();
1457 	regs->asc_fifo = ASC_MAX_OFFSET;
1458 	/* state to resume after we see the sync reply message */
1459 	state->script = asc->script + 2;
1460 	state->msglen = 0;
1461 	return (1);
1462 }
1463 
1464 /* ARGSUSED */
1465 static int
1466 asc_replysync(asc, status, ss, ir)
1467 	register asc_softc_t asc;
1468 	register int status, ss, ir;
1469 {
1470 	register asc_regmap_t *regs = asc->regs;
1471 	register State *state = &asc->st[asc->target];
1472 
1473 #ifdef DEBUG
1474 	if (asc_debug > 2)
1475 		printf("asc_replysync: %x %x\n",
1476 			asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
1477 			state->sync_offset);
1478 #endif
1479 	/* send synchronous transfer in response to a request */
1480 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1481 	MachEmptyWriteBuffer();
1482 	regs->asc_fifo = 3;
1483 	MachEmptyWriteBuffer();
1484 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1485 	MachEmptyWriteBuffer();
1486 	regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
1487 	MachEmptyWriteBuffer();
1488 	regs->asc_fifo = state->sync_offset;
1489 	regs->asc_cmd = ASC_CMD_XFER_INFO;
1490 	readback(regs->asc_cmd);
1491 
1492 	/* return to the appropriate script */
1493 	if (!state->script) {
1494 #ifdef DEBUG
1495 		asc_DumpLog("asc_replsync");
1496 #endif
1497 		panic("asc_replysync");
1498 	}
1499 	asc->script = state->script;
1500 	state->script = (script_t *)0;
1501 	return (0);
1502 }
1503 
1504 /* ARGSUSED */
1505 static int
1506 asc_msg_in(asc, status, ss, ir)
1507 	register asc_softc_t asc;
1508 	register int status, ss, ir;
1509 {
1510 	register asc_regmap_t *regs = asc->regs;
1511 	register State *state = &asc->st[asc->target];
1512 	register int msg;
1513 	int i;
1514 
1515 	/* read one message byte */
1516 	msg = regs->asc_fifo;
1517 #ifdef DEBUG
1518 	if (asc_logp == asc_log)
1519 		asc_log[NLOG - 1].msg = msg;
1520 	else
1521 		asc_logp[-1].msg = msg;
1522 #endif
1523 
1524 	/* check for multi-byte message */
1525 	if (state->msglen != 0) {
1526 		/* first byte is the message length */
1527 		if (state->msglen < 0) {
1528 			state->msglen = msg;
1529 			return (1);
1530 		}
1531 		if (state->msgcnt >= state->msglen)
1532 			goto abort;
1533 		state->msg_in[state->msgcnt++] = msg;
1534 
1535 		/* did we just read the last byte of the message? */
1536 		if (state->msgcnt != state->msglen)
1537 			return (1);
1538 
1539 		/* process an extended message */
1540 #ifdef DEBUG
1541 		if (asc_debug > 2)
1542 			printf("asc_msg_in: msg %x %x %x\n",
1543 				state->msg_in[0],
1544 				state->msg_in[1],
1545 				state->msg_in[2]);
1546 #endif
1547 		switch (state->msg_in[0]) {
1548 		case SCSI_SYNCHRONOUS_XFER:
1549 			state->flags |= DID_SYNC;
1550 			state->sync_offset = state->msg_in[2];
1551 
1552 			/* convert SCSI period to ASC period */
1553 			i = state->msg_in[1] / asc->tb_ticks;
1554 			if (i < asc->min_period)
1555 				i = asc->min_period;
1556 			else if (i >= asc->max_period) {
1557 				/* can't do sync transfer, period too long */
1558 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
1559 					asc - asc_softc, asc->target, i);
1560 				i = asc->max_period;
1561 				state->sync_offset = 0;
1562 			}
1563 			if ((i * asc->tb_ticks) != state->msg_in[1])
1564 				i++;
1565 			state->sync_period = i & 0x1F;
1566 
1567 			/*
1568 			 * If this is a request, check minimums and
1569 			 * send back an acknowledge.
1570 			 */
1571 			if (!(state->flags & TRY_SYNC)) {
1572 				regs->asc_cmd = ASC_CMD_SET_ATN;
1573 				readback(regs->asc_cmd);
1574 				MachEmptyWriteBuffer();
1575 
1576 				if (state->sync_period < asc->min_period)
1577 					state->sync_period =
1578 						asc->min_period;
1579 				if (state->sync_offset > ASC_MAX_OFFSET)
1580 					state->sync_offset =
1581 						ASC_MAX_OFFSET;
1582 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1583 				regs->asc_syn_p = state->sync_period;
1584 				readback(regs->asc_syn_p);
1585 				regs->asc_syn_o = state->sync_offset;
1586 				readback(regs->asc_syn_o);
1587 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
1588 				readback(regs->asc_cmd);
1589 				return (0);
1590 			}
1591 
1592 			regs->asc_syn_p = state->sync_period;
1593 			readback(regs->asc_syn_p);
1594 			regs->asc_syn_o = state->sync_offset;
1595 			readback(regs->asc_syn_o);
1596 			goto done;
1597 
1598 		default:
1599 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
1600 				asc - asc_softc, asc->target,
1601 				state->msg_in[0]);
1602 			goto reject;
1603 		}
1604 	}
1605 
1606 	/* process first byte of a message */
1607 #ifdef DEBUG
1608 	if (asc_debug > 2)
1609 		printf("asc_msg_in: msg %x\n", msg);
1610 #endif
1611 	switch (msg) {
1612 #if 0
1613 	case SCSI_MESSAGE_REJECT:
1614 		printf(" did not like SYNCH xfer "); /* XXX */
1615 		state->flags |= DID_SYNC;
1616 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1617 		readback(regs->asc_cmd);
1618 		status = asc_wait(regs, ASC_CSR_INT);
1619 		ir = regs->asc_intr;
1620 		/* some just break out here, some dont */
1621 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1622 			regs->asc_fifo = SCSI_ABORT;
1623 			regs->asc_cmd = ASC_CMD_XFER_INFO;
1624 			readback(regs->asc_cmd);
1625 			status = asc_wait(regs, ASC_CSR_INT);
1626 			ir = regs->asc_intr;
1627 		}
1628 		if (ir & ASC_INT_DISC) {
1629 			asc_end(asc, status, 0, ir);
1630 			return (0);
1631 		}
1632 		goto status;
1633 #endif
1634 
1635 	case SCSI_EXTENDED_MSG: /* read an extended message */
1636 		/* setup to read message length next */
1637 		state->msglen = -1;
1638 		state->msgcnt = 0;
1639 		return (1);
1640 
1641 	case SCSI_NO_OP:
1642 		break;
1643 
1644 	case SCSI_SAVE_DATA_POINTER:
1645 		/* expect another message */
1646 		return (1);
1647 
1648 	case SCSI_RESTORE_POINTERS:
1649 		/*
1650 		 * Need to do the following if resuming synchonous data in
1651 		 * on an odd byte boundary.
1652 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1653 		 */
1654 		break;
1655 
1656 	case SCSI_DISCONNECT:
1657 		if (state->flags & DISCONN)
1658 			goto abort;
1659 		state->flags |= DISCONN;
1660 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1661 		readback(regs->asc_cmd);
1662 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1663 		return (0);
1664 
1665 	default:
1666 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
1667 			asc - asc_softc, asc->target, msg);
1668 	reject:
1669 		/* request a message out before acknowledging this message */
1670 		state->msg_out = SCSI_MESSAGE_REJECT;
1671 		regs->asc_cmd = ASC_CMD_SET_ATN;
1672 		readback(regs->asc_cmd);
1673 		MachEmptyWriteBuffer();
1674 	}
1675 
1676 done:
1677 	/* return to original script */
1678 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
1679 	readback(regs->asc_cmd);
1680 	if (!state->script) {
1681 	abort:
1682 #ifdef DEBUG
1683 		asc_DumpLog("asc_msg_in");
1684 #endif
1685 		panic("asc_msg_in");
1686 	}
1687 	asc->script = state->script;
1688 	state->script = (script_t *)0;
1689 	return (0);
1690 }
1691 
1692 /* ARGSUSED */
1693 static int
1694 asc_disconnect(asc, status, ss, ir)
1695 	register asc_softc_t asc;
1696 	register int status, ss, ir;
1697 {
1698 	register State *state = &asc->st[asc->target];
1699 
1700 	asc->target = -1;
1701 	asc->state = ASC_STATE_RESEL;
1702 	return (1);
1703 }
1704 
1705 /*
1706  * DMA handling routines. For a turbochannel device, just set the dmar
1707  * for the I/O ASIC, handle the actual DMA interface.
1708  */
1709 static void
1710 tb_dma_start(asc, state, cp, flag)
1711 	asc_softc_t asc;
1712 	State *state;
1713 	caddr_t cp;
1714 	int flag;
1715 {
1716 
1717 	if (flag == ASCDMA_WRITE)
1718 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
1719 	else
1720 		*asc->dmar = ASC_DMA_ADDR(cp);
1721 }
1722 
1723 static void
1724 tb_dma_end(asc, state, flag)
1725 	asc_softc_t asc;
1726 	State *state;
1727 	int flag;
1728 {
1729 
1730 }
1731 
1732 static void
1733 asic_dma_start(asc, state, cp, flag)
1734 	asc_softc_t asc;
1735 	State *state;
1736 	caddr_t cp;
1737 	int flag;
1738 {
1739 	register volatile u_int *ssr = (volatile u_int *)
1740 		ASIC_REG_CSR(asic_base);
1741 	u_int phys, nphys;
1742 
1743 	/* stop DMA engine first */
1744 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1745 	* ((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0;
1746 
1747 	phys = MACH_CACHED_TO_PHYS(cp);
1748 	cp = (caddr_t)pmax_trunc_page(cp + NBPG);
1749 	nphys = MACH_CACHED_TO_PHYS(cp);
1750 
1751 	asc->dma_next = cp;
1752 	asc->dma_xfer = state->dmalen - (nphys - phys);
1753 
1754 	*(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) =
1755 		ASIC_DMA_ADDR(phys);
1756 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
1757 		ASIC_DMA_ADDR(nphys);
1758 	if (flag == ASCDMA_READ)
1759 		*ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI;
1760 	else
1761 		*ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI;
1762 	MachEmptyWriteBuffer();
1763 }
1764 
1765 static void
1766 asic_dma_end(asc, state, flag)
1767 	asc_softc_t asc;
1768 	State *state;
1769 	int flag;
1770 {
1771 	register volatile u_int *ssr = (volatile u_int *)
1772 		ASIC_REG_CSR(asic_base);
1773 	int nb;
1774 
1775 	*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1776 	*((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1;
1777 	*((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1;
1778 	MachEmptyWriteBuffer();
1779 
1780 	if (flag == ASCDMA_READ) {
1781 		MachFlushDCache(MACH_PHYS_TO_CACHED(
1782 		    MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
1783 		if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) {
1784 			/* pick up last upto6 bytes, sigh. */
1785 			register u_short *to;
1786 			register int w;
1787 
1788 			/* Last byte really xferred is.. */
1789 			to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1));
1790 			w = *(int *)ASIC_REG_SCSI_SDR0(asic_base);
1791 			*to++ = w;
1792 			if (--nb > 0) {
1793 				w >>= 16;
1794 				*to++ = w;
1795 			}
1796 			if (--nb > 0) {
1797 				w = *(int *)ASIC_REG_SCSI_SDR1(asic_base);
1798 				*to++ = w;
1799 			}
1800 		}
1801 	}
1802 }
1803 
1804 #ifdef notdef
1805 /*
1806  * Called by asic_intr() for scsi dma pointer update interrupts.
1807  */
1808 void
1809 asc_dma_intr()
1810 {
1811 	asc_softc_t asc = &asc_softc[0];
1812 	u_int next_phys;
1813 
1814 	asc->dma_xfer -= NBPG;
1815 	if (asc->dma_xfer <= -NBPG) {
1816 		volatile u_int *ssr = (volatile u_int *)
1817 			ASIC_REG_CSR(asic_base);
1818 		*ssr &= ~ASIC_CSR_DMAEN_SCSI;
1819 	} else {
1820 		asc->dma_next += NBPG;
1821 		next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
1822 	}
1823 	*(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) =
1824 		ASIC_DMA_ADDR(next_phys);
1825 	MachEmptyWriteBuffer();
1826 }
1827 #endif
1828 
1829 #ifdef DEBUG
1830 asc_DumpLog(str)
1831 	char *str;
1832 {
1833 	register struct asc_log *lp;
1834 	register u_int status;
1835 
1836 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
1837 		asc_debug_bn, asc_debug_sz);
1838 	lp = asc_logp + 1;
1839 	if (lp > &asc_log[NLOG])
1840 		lp = asc_log;
1841 	while (lp != asc_logp) {
1842 		status = lp->status;
1843 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
1844 			status >> 24,
1845 			lp->target,
1846 			(status >> 16) & 0xFF,
1847 			(status >> 8) & 0xFF,
1848 			status & 0XFF,
1849 			lp->state,
1850 			asc_scripts[lp->state].condition,
1851 			lp->msg);
1852 		if (++lp >= &asc_log[NLOG])
1853 			lp = asc_log;
1854 	}
1855 }
1856 #endif
1857 
1858 #endif	/* NASC > 0 */
1859