xref: /original-bsd/sys/pmax/dev/asc.c (revision 753853ba)
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.2 (Berkeley) 03/14/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 int	script_nop();			/* when nothing needed */
212 int	asc_end();			/* all come to an end */
213 int	asc_get_status();		/* get status from target */
214 int	asc_dma_in();			/* start reading data from target */
215 int	asc_last_dma_in();		/* cleanup after all data is read */
216 int	asc_resume_in();		/* resume data in after a message */
217 int	asc_resume_dma_in();		/* resume DMA after a disconnect */
218 int	asc_dma_out();			/* send data to target via dma */
219 int	asc_last_dma_out();		/* cleanup after all data is written */
220 int	asc_resume_out();		/* resume data out after a message */
221 int	asc_resume_dma_out();		/* resume DMA after a disconnect */
222 int	asc_sendsync();			/* negotiate sync xfer */
223 int	asc_replysync();		/* negotiate sync xfer */
224 int	asc_msg_in();			/* process a message byte */
225 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_GET_STATUS]},
305 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 13 */
306 		script_nop, ASC_CMD_XFER_INFO,
307 		&asc_scripts[SCRIPT_GET_STATUS]},
308 	{SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN),			/* 14 */
309 		asc_msg_in, ASC_CMD_MSG_ACPT,
310 		&asc_scripts[SCRIPT_GET_STATUS]},
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 FIRST_DMA	0x02	/* true if no data DMA started yet */
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 	volatile 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 = (volatile 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, 0);
607 	asc_logp->target = asc->target;
608 	asc_logp->state = 0;
609 	if (++asc_logp >= &asc_log[NLOG])
610 		asc_logp = asc_log;
611 #endif
612 
613 	/*
614 	 * Init the chip and target state.
615 	 */
616 	regs->asc_cmd = ASC_CMD_FLUSH;
617 	state->flags = FIRST_DMA | (state->flags & DID_SYNC);
618 	state->error = 0;
619 	state->script = (script_t *)0;
620 	state->msg_out = SCSI_NO_OP;
621 
622 	/*
623 	 * Copy command data to the DMA buffer.
624 	 */
625 	len = scsicmd->cmdlen;
626 	state->dmalen = len;
627 	bcopy(scsicmd->cmd, state->dmaBufAddr, len);
628 
629 	/* check for simple SCSI command with no data transfer */
630 	if ((state->buflen = scsicmd->buflen) == 0) {
631 		/* check for sync negotiation */
632 		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&
633 		    !(state->flags & DID_SYNC)) {
634 			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
635 			state->flags |= TRY_SYNC;
636 		} else
637 			asc->script = &asc_scripts[SCRIPT_SIMPLE];
638 		state->buf = (char *)0;
639 	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {
640 		int cnt;
641 
642 		asc->script = &asc_scripts[SCRIPT_DATA_OUT];
643 
644 		/* setup to write first chunk */
645 		state->flags |= DMA_OUT;
646 		state->buf = scsicmd->buf;
647 		cnt = state->dmaBufSize - len;
648 		if (cnt > state->buflen)
649 			cnt = state->buflen;
650 		else printf("can't write in one chunk cnt %d buflen %d\n",
651 			cnt, state->buflen); /* XXX */
652 		state->dmalen = cnt;
653 		bcopy(state->buf, state->dmaBufAddr + len, cnt);
654 	} else {
655 		asc->script = &asc_scripts[SCRIPT_DATA_IN];
656 		state->buf = scsicmd->buf;
657 		state->flags |= DMA_IN;
658 	}
659 
660 	/* preload the FIFO with the message to be sent */
661 	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
662 
663 	/* start the asc */
664 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
665 	ASC_TC_PUT(regs, len);
666 
667 	regs->asc_dbus_id = target;
668 	regs->asc_syn_p = state->sync_period;
669 	regs->asc_syn_o = state->sync_offset;
670 
671 	if (state->flags & TRY_SYNC)
672 		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA;
673 	else
674 		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;
675 }
676 
677 /*
678  * Interrupt routine
679  *	Take interrupts from the chip
680  *
681  * Implementation:
682  *	Move along the current command's script if
683  *	all is well, invoke error handler if not.
684  */
685 void
686 asc_intr(unit)
687 	int unit;
688 {
689 	register asc_softc_t asc = &asc_softc[unit];
690 	register asc_regmap_t *regs = asc->regs;
691 	register State *state;
692 	register script_t *scpt;
693 	register int ss, ir, status;
694 
695 again:
696 	/* collect ephemeral information */
697 	status = regs->asc_status;
698 	ss = regs->asc_ss;
699 	ir = regs->asc_intr;	/* this resets the previous two */
700 	scpt = asc->script;
701 
702 #ifdef DEBUG
703 	asc_logp->status = PACK(unit, status, ss, ir);
704 	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
705 	asc_logp->state = scpt - asc_scripts;
706 	asc_logp->msg = -1;
707 	if (++asc_logp >= &asc_log[NLOG])
708 		asc_logp = asc_log;
709 	if (asc_debug > 2)
710 		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
711 			status, ss, ir, scpt - asc_scripts, scpt->condition);
712 #endif
713 
714 	/* check the expected state */
715 	if (SCRIPT_MATCH(ir, status) == scpt->condition) {
716 		/*
717 		 * Perform the appropriate operation, then proceed.
718 		 */
719 		if ((*scpt->action)(asc, status, ss, ir)) {
720 			regs->asc_cmd = scpt->command;
721 			asc->script = scpt->next;
722 		}
723 		goto done;
724 	}
725 
726 	/* check for message in or out */
727 	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
728 		register int len, fifo;
729 
730 		state = &asc->st[asc->target];
731 		switch (ASC_PHASE(status)) {
732 		case ASC_PHASE_MSG_IN:
733 			break;
734 
735 		case ASC_PHASE_MSG_OUT:
736 			regs->asc_fifo = state->msg_out;
737 			state->msg_out = SCSI_NO_OP;
738 			regs->asc_cmd = ASC_CMD_XFER_INFO;
739 			goto done;
740 
741 		case ASC_PHASE_STATUS:
742 			asc_DumpLog("asc_intr: status"); /* XXX */
743 			/* probably an error in the SCSI command */
744 			asc->script = &asc_scripts[SCRIPT_GET_STATUS];
745 			regs->asc_cmd = ASC_CMD_I_COMPLETE;
746 			goto done;
747 
748 		default:
749 			goto abort;
750 		}
751 
752 		if (state->script)
753 			goto abort;
754 
755 		/* check for DMA in progress */
756 		ASC_TC_GET(regs, len);
757 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
758 		/* flush any data in the FIFO */
759 		if (fifo) {
760 			printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n",
761 				state->flags, state->dmalen,
762 				len, fifo); /* XXX */
763 			len += fifo;
764 			regs->asc_cmd = ASC_CMD_FLUSH;
765 			MachEmptyWriteBuffer();
766 		}
767 		if (len) {
768 			/* save number of bytes still to be sent or received */
769 			state->dmaresid = len;
770 			/* setup state to resume to */
771 			if (state->flags & DMA_IN)
772 				state->script =
773 					&asc_scripts[SCRIPT_RESUME_DMA_IN];
774 			else if (state->flags & DMA_OUT)
775 				state->script =
776 					&asc_scripts[SCRIPT_RESUME_DMA_OUT];
777 			else
778 				state->script = asc->script;
779 		} else {
780 			/* setup state to resume to */
781 			if (state->flags & DMA_IN) {
782 				if (!(state->flags & FIRST_DMA)) {
783 					len = state->dmalen;
784 					bcopy(state->dmaBufAddr, state->buf,
785 						len);
786 					state->buf += len;
787 					state->buflen -= len;
788 				} else
789 					state->flags &= ~FIRST_DMA;
790 				if (state->buflen)
791 					state->script =
792 					    &asc_scripts[SCRIPT_RESUME_IN];
793 				else
794 					state->script =
795 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
796 			} else if (state->flags & DMA_OUT) {
797 				/*
798 				 * If this is the last chunk, the next expected
799 				 * state is to get status.
800 				 */
801 				len = state->dmalen;
802 				state->buf += len;
803 				state->buflen -= len;
804 				if (state->buflen)
805 					state->script =
806 					    &asc_scripts[SCRIPT_RESUME_OUT];
807 				else
808 					state->script =
809 					    &asc_scripts[SCRIPT_RESUME_NO_DATA];
810 			} else
811 				state->script = asc->script;
812 		}
813 
814 		/* setup to receive a message */
815 		asc->script = &asc_scripts[SCRIPT_MSG_IN];
816 		state->msglen = 0;
817 		regs->asc_cmd = ASC_CMD_XFER_INFO;
818 		goto done;
819 	}
820 
821 	/* check for SCSI bus reset */
822 	if (ir & ASC_INT_RESET) {
823 		register int i;
824 
825 		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);
826 		/* need to flush any pending commands */
827 		for (i = 0; i < ASC_NCMD; i++) {
828 			if (!asc->cmd[i])
829 				continue;
830 			asc->st[i].error = EIO;
831 			asc_end(asc, 0, 0, 0);
832 		}
833 		/* rearbitrate synchronous offset */
834 		for (i = 0; i < ASC_NCMD; i++) {
835 			asc->st[i].sync_offset = 0;
836 			asc->st[i].flags = 0;
837 		}
838 		asc->target = -1;
839 		return;
840 	}
841 
842 	/* check for command errors */
843 	if (ir & ASC_INT_ILL)
844 		goto abort;
845 
846 	/* check for disconnect */
847 	if (ir & ASC_INT_DISC) {
848 		state = &asc->st[asc->target];
849 		switch (ASC_SS(ss)) {
850 		case 0: /* device did not respond */
851 			state->error = ENXIO;
852 			asc_end(asc, status, ss, ir);
853 			return;
854 
855 		default:
856 			goto abort;
857 		}
858 	}
859 
860 	/* check for reselect */
861 	if (ir & ASC_INT_RESEL) {
862 		unsigned fifo, id, msg;
863 
864 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
865 		if (fifo < 2)
866 			goto abort;
867 		/* read unencoded SCSI ID and convert to binary */
868 		msg = regs->asc_fifo & asc->myidmask;
869 		for (id = 0; (msg & 1) == 0; id++)
870 			msg >>= 1;
871 		/* read identify message */
872 		msg = regs->asc_fifo;
873 #ifdef DEBUG
874 		if (asc_logp == asc_log)
875 			asc_log[NLOG - 1].msg = msg;
876 		else
877 			asc_logp[-1].msg = msg;
878 #endif
879 		if (asc->state != ASC_STATE_RESEL)
880 			goto abort;
881 		asc->state = ASC_STATE_BUSY;
882 		asc->target = id;
883 		state = &asc->st[id];
884 		asc->script = state->script;
885 		state->script = (script_t *)0;
886 		if (!(state->flags & DISCONN))
887 			goto abort;
888 		state->flags &= ~DISCONN;
889 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
890 		goto done;
891 	}
892 
893 	/* check if we are being selected as a target */
894 	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
895 		goto abort;
896 
897 	/* must be just a ASC_INT_FC */
898 done:
899 	MachEmptyWriteBuffer();
900 	if (regs->asc_status & ASC_CSR_INT)
901 		goto again;
902 	return;
903 
904 abort:
905 #ifdef DEBUG
906 	asc_DumpLog("asc_intr");
907 #endif
908 #if 0
909 	panic("asc_intr");
910 #else
911 	for (;;);
912 #endif
913 }
914 
915 /*
916  * All the many little things that the interrupt
917  * routine might switch to.
918  */
919 
920 /* ARGSUSED */
921 static int
922 script_nop(asc, status, ss, ir)
923 	register asc_softc_t asc;
924 	register int status, ss, ir;
925 {
926 	return (1);
927 }
928 
929 /* ARGSUSED */
930 static int
931 asc_get_status(asc, status, ss, ir)
932 	register asc_softc_t asc;
933 	register int status, ss, ir;
934 {
935 	register asc_regmap_t *regs = asc->regs;
936 	register int data;
937 
938 	/*
939 	 * Get the last two bytes in the FIFO.
940 	 */
941 	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
942 		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */
943 		if (data < 2) {
944 			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
945 			return (0);
946 		}
947 		do {
948 			data = regs->asc_fifo;
949 		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
950 	}
951 
952 	/* save the status byte */
953 	asc->st[asc->target].statusByte = data = regs->asc_fifo;
954 #ifdef DEBUG
955 	if (asc_logp == asc_log)
956 		asc_log[NLOG - 1].msg = data;
957 	else
958 		asc_logp[-1].msg = data;
959 #endif
960 
961 	/* get the (presumed) command_complete message */
962 	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
963 		return (1);
964 
965 #ifdef DEBUG
966 	printf("asc_get_status: status %x cmd %x\n",
967 		asc->st[asc->target].statusByte, data);
968 	asc_DumpLog("asc_get_status");
969 #endif
970 	return (0);
971 }
972 
973 /* ARGSUSED */
974 static int
975 asc_end(asc, status, ss, ir)
976 	register asc_softc_t asc;
977 	register int status, ss, ir;
978 {
979 	register ScsiCmd *scsicmd;
980 	register State *state;
981 	register int i, target;
982 
983 	asc->state = ASC_STATE_IDLE;
984 	target = asc->target;
985 	asc->target = -1;
986 	scsicmd = asc->cmd[target];
987 	asc->cmd[target] = (ScsiCmd *)0;
988 	state = &asc->st[target];
989 
990 #ifdef DEBUG
991 	if (asc_debug > 1) {
992 		printf("asc_end: %s target %d cmd %x err %d resid %d\n",
993 			scsicmd->sd->sd_driver->d_name, target,
994 			scsicmd->cmd[0], state->error, state->buflen);
995 	}
996 #endif
997 #ifdef DIAGNOSTIC
998 	if (target < 0 || !scsicmd)
999 		panic("asc_end");
1000 #endif
1001 
1002 	/* look for disconnected devices */
1003 	for (i = 0; i < ASC_NCMD; i++) {
1004 		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
1005 			continue;
1006 		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1007 		asc->state = ASC_STATE_RESEL;
1008 		asc->script = &asc_scripts[SCRIPT_RESEL];
1009 		break;
1010 	}
1011 
1012 	/* look for another device that is ready */
1013 	for (i = 0; i < ASC_NCMD; i++) {
1014 		/* don't restart a disconnected command */
1015 		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
1016 			continue;
1017 		asc_startcmd(asc, i);
1018 		break;
1019 	}
1020 
1021 	/* signal device driver that the command is done */
1022 	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,
1023 		state->buflen, state->statusByte);
1024 
1025 	return (0);
1026 }
1027 
1028 /* ARGSUSED */
1029 static int
1030 asc_dma_in(asc, status, ss, ir)
1031 	register asc_softc_t asc;
1032 	register int status, ss, ir;
1033 {
1034 	register asc_regmap_t *regs = asc->regs;
1035 	register State *state = &asc->st[asc->target];
1036 	register int len, fifo;
1037 
1038 	/* check for previous chunk in buffer */
1039 	if (!(state->flags & FIRST_DMA)) {
1040 		/*
1041 		 * Only count bytes that have been copied to memory.
1042 		 * There may be some bytes in the FIFO if synchonous transfers
1043 		 * are in progress.
1044 		 */
1045 		ASC_TC_GET(regs, len);
1046 		len = state->dmalen - len;
1047 		bcopy(state->dmaBufAddr, state->buf, len);
1048 		state->buf += len;
1049 		state->buflen -= len;
1050 	} else
1051 		state->flags &= ~FIRST_DMA;
1052 
1053 	/* setup to start reading the next chunk */
1054 	len = state->buflen;
1055 	if (len > state->dmaBufSize)
1056 		len = state->dmaBufSize;
1057 	state->dmalen = len;
1058 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr);
1059 	ASC_TC_PUT(regs, len);
1060 #ifdef DEBUG
1061 	if (asc_debug > 2)
1062 		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1063 #endif
1064 
1065 	/* check for next chunk */
1066 	if (len != state->buflen) {
1067 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1068 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1069 		return (0);
1070 	}
1071 	return (1);
1072 }
1073 
1074 /* ARGSUSED */
1075 static int
1076 asc_last_dma_in(asc, status, ss, ir)
1077 	register asc_softc_t asc;
1078 	register int status, ss, ir;
1079 {
1080 	register asc_regmap_t *regs = asc->regs;
1081 	register State *state = &asc->st[asc->target];
1082 	register int len, fifo;
1083 
1084 	/* copy data from buffer to main memory */
1085 	ASC_TC_GET(regs, len);
1086 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1087 #ifdef DEBUG
1088 #if 0
1089 	if (asc_debug > 2)
1090 #else
1091 	if (asc_debug > 2 || len || fifo) /* XXX */
1092 #endif
1093 		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1094 			state->buflen, state->dmalen, len, fifo);
1095 #endif
1096 	if (fifo) {
1097 		/* device must be trying to send more than we expect */
1098 		regs->asc_cmd = ASC_CMD_FLUSH;
1099 		MachEmptyWriteBuffer();
1100 	}
1101 	len = state->dmalen - len;
1102 	state->buflen -= len;
1103 	bcopy(state->dmaBufAddr, state->buf, len);
1104 
1105 	return (1);
1106 }
1107 
1108 /* ARGSUSED */
1109 static int
1110 asc_resume_in(asc, status, ss, ir)
1111 	register asc_softc_t asc;
1112 	register int status, ss, ir;
1113 {
1114 	register asc_regmap_t *regs = asc->regs;
1115 	register State *state = &asc->st[asc->target];
1116 	register int len;
1117 
1118 	/* setup to start reading the next chunk */
1119 	len = state->buflen;
1120 	if (len > state->dmaBufSize)
1121 		len = state->dmaBufSize;
1122 	state->dmalen = len;
1123 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr);
1124 	ASC_TC_PUT(regs, len);
1125 #ifdef DEBUG
1126 	if (asc_debug > 2)
1127 		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1128 			len);
1129 #endif
1130 
1131 	/* check for next chunk */
1132 	if (len != state->buflen) {
1133 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1134 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1135 		return (0);
1136 	}
1137 	return (1);
1138 }
1139 
1140 /* ARGSUSED */
1141 static int
1142 asc_resume_dma_in(asc, status, ss, ir)
1143 	register asc_softc_t asc;
1144 	register int status, ss, ir;
1145 {
1146 	register asc_regmap_t *regs = asc->regs;
1147 	register State *state = &asc->st[asc->target];
1148 	register int len, off;
1149 
1150 	/* setup to finish reading the current chunk */
1151 	len = state->dmaresid;
1152 	off = state->dmalen - len;
1153 	if ((off & 1) && state->sync_offset) {
1154 		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1155 			state->dmalen, len, off); /* XXX */
1156 		regs->asc_res_fifo = state->dmaBufAddr[off];
1157 	}
1158 	*asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off);
1159 	ASC_TC_PUT(regs, len);
1160 #ifdef DEBUG
1161 	if (asc_debug > 2)
1162 		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1163 			state->dmalen, state->buflen, len, off);
1164 #endif
1165 
1166 	/* check for next chunk */
1167 	if (state->dmalen != state->buflen) {
1168 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1169 		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1170 		return (0);
1171 	}
1172 	return (1);
1173 }
1174 
1175 /* ARGSUSED */
1176 static int
1177 asc_dma_out(asc, status, ss, ir)
1178 	register asc_softc_t asc;
1179 	register int status, ss, ir;
1180 {
1181 	register asc_regmap_t *regs = asc->regs;
1182 	register State *state = &asc->st[asc->target];
1183 	register int len, fifo;
1184 
1185 	if (!(state->flags & FIRST_DMA)) {
1186 		/* check to be sure previous chunk was finished */
1187 		ASC_TC_GET(regs, len);
1188 		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1189 		if (len || fifo)
1190 			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1191 				state->buflen, state->dmalen, len, fifo); /* XXX */
1192 		len += fifo;
1193 		len = state->dmalen - len;
1194 		state->buflen -= len;
1195 		state->buf += len;
1196 
1197 		/* setup for this chunck */
1198 		len = state->buflen;
1199 		if (len > state->dmaBufSize)
1200 			len = state->dmaBufSize;
1201 		state->dmalen = len;
1202 		bcopy(state->buf, state->dmaBufAddr, len);
1203 		*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
1204 	} else
1205 		state->flags &= ~FIRST_DMA;
1206 
1207 	len = state->dmalen;
1208 	ASC_TC_PUT(regs, len);
1209 #ifdef DEBUG
1210 	if (asc_debug > 2)
1211 		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
1212 #endif
1213 
1214 	/* check for next chunk */
1215 	if (len != state->buflen) {
1216 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1217 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1218 		return (0);
1219 	}
1220 	return (1);
1221 }
1222 
1223 /* ARGSUSED */
1224 static int
1225 asc_last_dma_out(asc, status, ss, ir)
1226 	register asc_softc_t asc;
1227 	register int status, ss, ir;
1228 {
1229 	register asc_regmap_t *regs = asc->regs;
1230 	register State *state = &asc->st[asc->target];
1231 	register int len, fifo;
1232 
1233 	ASC_TC_GET(regs, len);
1234 	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1235 #ifdef DEBUG
1236 #if 0
1237 	if (asc_debug > 2)
1238 #else
1239 	if (asc_debug > 2 || len || fifo) /* XXX */
1240 #endif
1241 		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1242 			state->buflen, state->dmalen, len, fifo); /* XXX */
1243 #endif
1244 	if (fifo) {
1245 		len += fifo;
1246 		regs->asc_cmd = ASC_CMD_FLUSH;
1247 		MachEmptyWriteBuffer();
1248 	}
1249 	len = state->dmalen - len;
1250 	state->buflen -= len;
1251 	return (1);
1252 }
1253 
1254 /* ARGSUSED */
1255 static int
1256 asc_resume_out(asc, status, ss, ir)
1257 	register asc_softc_t asc;
1258 	register int status, ss, ir;
1259 {
1260 	register asc_regmap_t *regs = asc->regs;
1261 	register State *state = &asc->st[asc->target];
1262 	register int len;
1263 
1264 	/* setup for this chunck */
1265 	len = state->buflen;
1266 	if (len > state->dmaBufSize)
1267 		len = state->dmaBufSize;
1268 	state->dmalen = len;
1269 	bcopy(state->buf, state->dmaBufAddr, len);
1270 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr);
1271 	ASC_TC_PUT(regs, len);
1272 #ifdef DEBUG
1273 	if (asc_debug > 2)
1274 		printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1275 			len);
1276 #endif
1277 
1278 	/* check for next chunk */
1279 	if (len != state->buflen) {
1280 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1281 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1282 		return (0);
1283 	}
1284 	return (1);
1285 }
1286 
1287 /* ARGSUSED */
1288 static int
1289 asc_resume_dma_out(asc, status, ss, ir)
1290 	register asc_softc_t asc;
1291 	register int status, ss, ir;
1292 {
1293 	register asc_regmap_t *regs = asc->regs;
1294 	register State *state = &asc->st[asc->target];
1295 	register int len, off;
1296 
1297 	/* setup to finish writing this chunk */
1298 	len = state->dmaresid;
1299 	off = state->dmalen - len;
1300 	if (off & 1) {
1301 		printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1302 			state->dmalen, len, off); /* XXX */
1303 		regs->asc_fifo = state->dmaBufAddr[off];
1304 		off++;
1305 		len--;
1306 	}
1307 	*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off);
1308 	ASC_TC_PUT(regs, len);
1309 #ifdef DEBUG
1310 	if (asc_debug > 2)
1311 		printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1312 			state->dmalen, state->buflen, len, off);
1313 #endif
1314 
1315 	/* check for next chunk */
1316 	if (state->dmalen != state->buflen) {
1317 		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1318 		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1319 		return (0);
1320 	}
1321 	return (1);
1322 }
1323 
1324 /* ARGSUSED */
1325 static int
1326 asc_sendsync(asc, status, ss, ir)
1327 	register asc_softc_t asc;
1328 	register int status, ss, ir;
1329 {
1330 	register asc_regmap_t *regs = asc->regs;
1331 
1332 	/*
1333 	 * Phase is MSG_OUT here.
1334 	 * Try sync negotiation, unless prohibited
1335 	 */
1336 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1337 	MachEmptyWriteBuffer();
1338 	regs->asc_fifo = 3;
1339 	MachEmptyWriteBuffer();
1340 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1341 	MachEmptyWriteBuffer();
1342 	regs->asc_fifo = SCSI_MIN_PERIOD;
1343 	MachEmptyWriteBuffer();
1344 	regs->asc_fifo = ASC_MAX_OFFSET;
1345 	return (1);
1346 }
1347 
1348 /* ARGSUSED */
1349 static int
1350 asc_replysync(asc, status, ss, ir)
1351 	register asc_softc_t asc;
1352 	register int status, ss, ir;
1353 {
1354 	register asc_regmap_t *regs = asc->regs;
1355 	register State *state = &asc->st[asc->target];
1356 
1357 #ifdef DEBUG
1358 	if (asc_debug > 2)
1359 		printf("asc_replysync: %x %x\n",
1360 			asc_to_scsi_period[state->sync_period],
1361 			state->sync_offset);
1362 #endif
1363 	/* send synchronous transfer in response to a request */
1364 	regs->asc_fifo = SCSI_EXTENDED_MSG;
1365 	MachEmptyWriteBuffer();
1366 	regs->asc_fifo = 3;
1367 	MachEmptyWriteBuffer();
1368 	regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1369 	MachEmptyWriteBuffer();
1370 	regs->asc_fifo = asc_to_scsi_period[state->sync_period];
1371 	MachEmptyWriteBuffer();
1372 	regs->asc_fifo = state->sync_offset;
1373 	regs->asc_cmd = ASC_CMD_XFER_INFO;
1374 
1375 	/* return to the appropriate script */
1376 	if (!state->script) {
1377 #ifdef DEBUG
1378 		asc_DumpLog("asc_replsync");
1379 #endif
1380 		panic("asc_replysync");
1381 	}
1382 	asc->script = state->script;
1383 	state->script = (script_t *)0;
1384 	return (0);
1385 }
1386 
1387 /* ARGSUSED */
1388 static int
1389 asc_msg_in(asc, status, ss, ir)
1390 	register asc_softc_t asc;
1391 	register int status, ss, ir;
1392 {
1393 	register asc_regmap_t *regs = asc->regs;
1394 	register State *state = &asc->st[asc->target];
1395 	register int msg;
1396 	int i;
1397 
1398 	/* read one message byte */
1399 	msg = regs->asc_fifo;
1400 #ifdef DEBUG
1401 	if (asc_logp == asc_log)
1402 		asc_log[NLOG - 1].msg = msg;
1403 	else
1404 		asc_logp[-1].msg = msg;
1405 #endif
1406 
1407 	/* check for multi-byte message */
1408 	if (state->msglen != 0) {
1409 		/* first byte is the message length */
1410 		if (state->msglen < 0) {
1411 			state->msglen = msg;
1412 			return (1);
1413 		}
1414 		if (state->msgcnt >= state->msglen)
1415 			goto abort;
1416 		state->msg_in[state->msgcnt++] = msg;
1417 
1418 		/* did we just read the last byte of the message? */
1419 		if (state->msgcnt != state->msglen)
1420 			return (1);
1421 
1422 		/* process an extended message */
1423 #ifdef DEBUG
1424 		if (asc_debug > 2)
1425 			printf("asc_msg_in: msg %x %x %x\n",
1426 				state->msg_in[0],
1427 				state->msg_in[1],
1428 				state->msg_in[2]);
1429 #endif
1430 		switch (state->msg_in[0]) {
1431 		case SCSI_SYNCHRONOUS_XFER:
1432 			state->flags |= DID_SYNC;
1433 			state->sync_offset = state->msg_in[2];
1434 
1435 			/* convert SCSI period to ASC period */
1436 			i = state->msg_in[1] / 10;
1437 			if (i < ASC_MIN_PERIOD)
1438 				i = ASC_MIN_PERIOD;
1439 			else if (i >= ASC_MAX_PERIOD) {
1440 				/* can't do sync transfer, period too long */
1441 				printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n",
1442 					asc - asc_softc, asc->target, i);
1443 				i = ASC_MAX_PERIOD;
1444 				state->sync_offset = 0;
1445 			}
1446 			if ((i * 10) != state->msg_in[1])
1447 				i++;
1448 			state->sync_period = i & 0x1F;
1449 
1450 			/*
1451 			 * If this is a request, check minimums and
1452 			 * send back an acknowledge.
1453 			 */
1454 			if (!(state->flags & TRY_SYNC)) {
1455 				regs->asc_cmd = ASC_CMD_SET_ATN;
1456 				MachEmptyWriteBuffer();
1457 
1458 				if (state->sync_period < ASC_MIN_PERIOD)
1459 					state->sync_period =
1460 						ASC_MIN_PERIOD;
1461 				if (state->sync_offset > ASC_MAX_OFFSET)
1462 					state->sync_offset =
1463 						ASC_MAX_OFFSET;
1464 				asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1465 				regs->asc_syn_p = state->sync_period;
1466 				regs->asc_syn_o = state->sync_offset;
1467 				regs->asc_cmd = ASC_CMD_MSG_ACPT;
1468 				return (0);
1469 			}
1470 
1471 			regs->asc_syn_p = state->sync_period;
1472 			regs->asc_syn_o = state->sync_offset;
1473 			goto done;
1474 
1475 		default:
1476 			printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n",
1477 				asc - asc_softc, asc->target,
1478 				state->msg_in[0]);
1479 			goto reject;
1480 		}
1481 	}
1482 
1483 	/* process first byte of a message */
1484 #ifdef DEBUG
1485 	if (asc_debug > 2)
1486 		printf("asc_msg_in: msg %x\n", msg);
1487 #endif
1488 	switch (msg) {
1489 #if 0
1490 	case SCSI_MESSAGE_REJECT:
1491 		printf(" did not like SYNCH xfer "); /* XXX */
1492 		state->flags |= DID_SYNC;
1493 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1494 		status = asc_wait(regs, ASC_CSR_INT);
1495 		ir = regs->asc_intr;
1496 		/* some just break out here, some dont */
1497 		if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1498 			regs->asc_fifo = SCSI_ABORT;
1499 			regs->asc_cmd = ASC_CMD_XFER_INFO;
1500 			status = asc_wait(regs, ASC_CSR_INT);
1501 			ir = regs->asc_intr;
1502 		}
1503 		if (ir & ASC_INT_DISC) {
1504 			asc_end(asc, status, 0, ir);
1505 			return (0);
1506 		}
1507 		goto status;
1508 #endif
1509 
1510 	case SCSI_EXTENDED_MSG: /* read an extended message */
1511 		/* setup to read message length next */
1512 		state->msglen = -1;
1513 		state->msgcnt = 0;
1514 		return (1);
1515 
1516 	case SCSI_NO_OP:
1517 		break;
1518 
1519 	case SCSI_SAVE_DATA_POINTER:
1520 		/* expect another message */
1521 		return (1);
1522 
1523 	case SCSI_RESTORE_POINTERS:
1524 		/*
1525 		 * Need to do the following if resuming synchonous data in
1526 		 * on an odd byte boundary.
1527 		regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1528 		 */
1529 		break;
1530 
1531 	case SCSI_DISCONNECT:
1532 		if (state->flags & DISCONN)
1533 			goto abort;
1534 		state->flags |= DISCONN;
1535 		regs->asc_cmd = ASC_CMD_MSG_ACPT;
1536 		asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1537 		return (0);
1538 
1539 	default:
1540 		printf("asc%d: SCSI device %d: rejecting message 0x%x\n",
1541 			asc - asc_softc, asc->target, msg);
1542 	reject:
1543 		/* request a message out before acknowledging this message */
1544 		state->msg_out = SCSI_MESSAGE_REJECT;
1545 		regs->asc_cmd = ASC_CMD_SET_ATN;
1546 		MachEmptyWriteBuffer();
1547 	}
1548 
1549 done:
1550 	/* return to original script */
1551 	regs->asc_cmd = ASC_CMD_MSG_ACPT;
1552 	if (!state->script) {
1553 	abort:
1554 #ifdef DEBUG
1555 		asc_DumpLog("asc_msg_in");
1556 #endif
1557 		panic("asc_msg_in");
1558 	}
1559 	asc->script = state->script;
1560 	state->script = (script_t *)0;
1561 	return (0);
1562 }
1563 
1564 /* ARGSUSED */
1565 static int
1566 asc_disconnect(asc, status, ss, ir)
1567 	register asc_softc_t asc;
1568 	register int status, ss, ir;
1569 {
1570 	register State *state = &asc->st[asc->target];
1571 
1572 	asc->target = -1;
1573 	asc->state = ASC_STATE_RESEL;
1574 	return (1);
1575 }
1576 
1577 #ifdef DEBUG
1578 asc_DumpLog(str)
1579 	char *str;
1580 {
1581 	register struct asc_log *lp;
1582 	register u_int status;
1583 
1584 	printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
1585 		asc_debug_bn, asc_debug_sz);
1586 	lp = asc_logp + 1;
1587 	if (lp > &asc_log[NLOG])
1588 		lp = asc_log;
1589 	while (lp != asc_logp) {
1590 		status = lp->status;
1591 		printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n",
1592 			status >> 24,
1593 			lp->target,
1594 			(status >> 16) & 0xFF,
1595 			(status >> 8) & 0xFF,
1596 			status & 0XFF,
1597 			lp->state,
1598 			asc_scripts[lp->state].condition,
1599 			lp->msg);
1600 		if (++lp >= &asc_log[NLOG])
1601 			lp = asc_log;
1602 	}
1603 }
1604 #endif
1605 
1606 #endif	/* NASC > 0 */
1607