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