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