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