asc.c revision 1.6.2.2 1 1.6.2.2 nathanw /* $NetBSD: asc.c,v 1.6.2.2 2002/06/24 22:03:43 nathanw Exp $ */
2 1.6.2.2 nathanw /* $OpenBSD: asc.c,v 1.9 1998/03/16 09:38:39 pefo Exp $ */
3 1.6.2.2 nathanw /* NetBSD: asc.c,v 1.10 1994/12/05 19:11:12 dean Exp */
4 1.6.2.2 nathanw
5 1.6.2.2 nathanw /*-
6 1.6.2.2 nathanw * Copyright (c) 1992, 1993
7 1.6.2.2 nathanw * The Regents of the University of California. All rights reserved.
8 1.6.2.2 nathanw *
9 1.6.2.2 nathanw * This code is derived from software contributed to Berkeley by
10 1.6.2.2 nathanw * Ralph Campbell and Rick Macklem.
11 1.6.2.2 nathanw *
12 1.6.2.2 nathanw * Redistribution and use in source and binary forms, with or without
13 1.6.2.2 nathanw * modification, are permitted provided that the following conditions
14 1.6.2.2 nathanw * are met:
15 1.6.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
16 1.6.2.2 nathanw * notice, this list of conditions and the following disclaimer.
17 1.6.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
18 1.6.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
19 1.6.2.2 nathanw * documentation and/or other materials provided with the distribution.
20 1.6.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
21 1.6.2.2 nathanw * must display the following acknowledgement:
22 1.6.2.2 nathanw * This product includes software developed by the University of
23 1.6.2.2 nathanw * California, Berkeley and its contributors.
24 1.6.2.2 nathanw * 4. Neither the name of the University nor the names of its contributors
25 1.6.2.2 nathanw * may be used to endorse or promote products derived from this software
26 1.6.2.2 nathanw * without specific prior written permission.
27 1.6.2.2 nathanw *
28 1.6.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.6.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.6.2.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.6.2.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.6.2.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.6.2.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.6.2.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.6.2.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.6.2.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.6.2.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.6.2.2 nathanw * SUCH DAMAGE.
39 1.6.2.2 nathanw *
40 1.6.2.2 nathanw * @(#)asc.c 8.3 (Berkeley) 7/3/94
41 1.6.2.2 nathanw */
42 1.6.2.2 nathanw
43 1.6.2.2 nathanw /*
44 1.6.2.2 nathanw * Mach Operating System
45 1.6.2.2 nathanw * Copyright (c) 1991,1990,1989 Carnegie Mellon University
46 1.6.2.2 nathanw * All Rights Reserved.
47 1.6.2.2 nathanw *
48 1.6.2.2 nathanw * Permission to use, copy, modify and distribute this software and its
49 1.6.2.2 nathanw * documentation is hereby granted, provided that both the copyright
50 1.6.2.2 nathanw * notice and this permission notice appear in all copies of the
51 1.6.2.2 nathanw * software, derivative works or modified versions, and any portions
52 1.6.2.2 nathanw * thereof, and that both notices appear in supporting documentation.
53 1.6.2.2 nathanw *
54 1.6.2.2 nathanw * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
55 1.6.2.2 nathanw * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
56 1.6.2.2 nathanw * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
57 1.6.2.2 nathanw *
58 1.6.2.2 nathanw * Carnegie Mellon requests users of this software to return to
59 1.6.2.2 nathanw *
60 1.6.2.2 nathanw * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
61 1.6.2.2 nathanw * School of Computer Science
62 1.6.2.2 nathanw * Carnegie Mellon University
63 1.6.2.2 nathanw * Pittsburgh PA 15213-3890
64 1.6.2.2 nathanw *
65 1.6.2.2 nathanw * any improvements or extensions that they make and grant Carnegie the
66 1.6.2.2 nathanw * rights to redistribute these changes.
67 1.6.2.2 nathanw */
68 1.6.2.2 nathanw
69 1.6.2.2 nathanw /*
70 1.6.2.2 nathanw * HISTORY
71 1.6.2.2 nathanw * Log: scsi_53C94_hdw.c,v
72 1.6.2.2 nathanw * Revision 2.5 91/02/05 17:45:07 mrt
73 1.6.2.2 nathanw * Added author notices
74 1.6.2.2 nathanw * [91/02/04 11:18:43 mrt]
75 1.6.2.2 nathanw *
76 1.6.2.2 nathanw * Changed to use new Mach copyright
77 1.6.2.2 nathanw * [91/02/02 12:17:20 mrt]
78 1.6.2.2 nathanw *
79 1.6.2.2 nathanw * Revision 2.4 91/01/08 15:48:24 rpd
80 1.6.2.2 nathanw * Added continuation argument to thread_block.
81 1.6.2.2 nathanw * [90/12/27 rpd]
82 1.6.2.2 nathanw *
83 1.6.2.2 nathanw * Revision 2.3 90/12/05 23:34:48 af
84 1.6.2.2 nathanw * Recovered from pmax merge.. and from the destruction of a disk.
85 1.6.2.2 nathanw * [90/12/03 23:40:40 af]
86 1.6.2.2 nathanw *
87 1.6.2.2 nathanw * Revision 2.1.1.1 90/11/01 03:39:09 af
88 1.6.2.2 nathanw * Created, from the DEC specs:
89 1.6.2.2 nathanw * "PMAZ-AA TURBOchannel SCSI Module Functional Specification"
90 1.6.2.2 nathanw * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
91 1.6.2.2 nathanw * And from the NCR data sheets
92 1.6.2.2 nathanw * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller"
93 1.6.2.2 nathanw * [90/09/03 af]
94 1.6.2.2 nathanw */
95 1.6.2.2 nathanw
96 1.6.2.2 nathanw /*
97 1.6.2.2 nathanw * File: scsi_53C94_hdw.h
98 1.6.2.2 nathanw * Author: Alessandro Forin, Carnegie Mellon University
99 1.6.2.2 nathanw * Date: 9/90
100 1.6.2.2 nathanw *
101 1.6.2.2 nathanw * Bottom layer of the SCSI driver: chip-dependent functions
102 1.6.2.2 nathanw *
103 1.6.2.2 nathanw * This file contains the code that is specific to the NCR 53C94
104 1.6.2.2 nathanw * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
105 1.6.2.2 nathanw * operation, and interrupt routine.
106 1.6.2.2 nathanw */
107 1.6.2.2 nathanw
108 1.6.2.2 nathanw /*
109 1.6.2.2 nathanw * This layer works based on small simple 'scripts' that are installed
110 1.6.2.2 nathanw * at the start of the command and drive the chip to completion.
111 1.6.2.2 nathanw * The idea comes from the specs of the NCR 53C700 'script' processor.
112 1.6.2.2 nathanw *
113 1.6.2.2 nathanw * There are various reasons for this, mainly
114 1.6.2.2 nathanw * - Performance: identify the common (successful) path, and follow it;
115 1.6.2.2 nathanw * at interrupt time no code is needed to find the current status
116 1.6.2.2 nathanw * - Code size: it should be easy to compact common operations
117 1.6.2.2 nathanw * - Adaptability: the code skeleton should adapt to different chips without
118 1.6.2.2 nathanw * terrible complications.
119 1.6.2.2 nathanw * - Error handling: and it is easy to modify the actions performed
120 1.6.2.2 nathanw * by the scripts to cope with strange but well identified sequences
121 1.6.2.2 nathanw *
122 1.6.2.2 nathanw */
123 1.6.2.2 nathanw
124 1.6.2.2 nathanw #include <sys/param.h>
125 1.6.2.2 nathanw #include <sys/systm.h>
126 1.6.2.2 nathanw #include <sys/dkstat.h>
127 1.6.2.2 nathanw #include <sys/buf.h>
128 1.6.2.2 nathanw #include <sys/proc.h>
129 1.6.2.2 nathanw #include <sys/conf.h>
130 1.6.2.2 nathanw #include <sys/errno.h>
131 1.6.2.2 nathanw #include <sys/device.h>
132 1.6.2.2 nathanw #include <uvm/uvm_extern.h>
133 1.6.2.2 nathanw
134 1.6.2.2 nathanw #include <dev/scsipi/scsi_all.h>
135 1.6.2.2 nathanw #include <dev/scsipi/scsipi_all.h>
136 1.6.2.2 nathanw #include <dev/scsipi/scsiconf.h>
137 1.6.2.2 nathanw
138 1.6.2.2 nathanw #include <mips/cache.h>
139 1.6.2.2 nathanw
140 1.6.2.2 nathanw #include <machine/cpu.h>
141 1.6.2.2 nathanw #include <machine/autoconf.h>
142 1.6.2.2 nathanw #include <machine/bus.h>
143 1.6.2.2 nathanw
144 1.6.2.2 nathanw #include <arc/jazz/jazziovar.h>
145 1.6.2.2 nathanw #include <arc/jazz/jazzdmatlbreg.h>
146 1.6.2.2 nathanw #include <arc/jazz/dma.h>
147 1.6.2.2 nathanw #include <arc/jazz/scsi.h>
148 1.6.2.2 nathanw #include <arc/jazz/ascreg.h>
149 1.6.2.2 nathanw #include <arc/jazz/ascvar.h>
150 1.6.2.2 nathanw
151 1.6.2.2 nathanw #include <arc/jazz/pica.h>
152 1.6.2.2 nathanw
153 1.6.2.2 nathanw
154 1.6.2.2 nathanw #define readback(a) { register int foo; foo = (a); }
155 1.6.2.2 nathanw
156 1.6.2.2 nathanw /*
157 1.6.2.2 nathanw * In 4ns ticks.
158 1.6.2.2 nathanw */
159 1.6.2.2 nathanw int asc_to_scsi_period[] = {
160 1.6.2.2 nathanw 32,
161 1.6.2.2 nathanw 33,
162 1.6.2.2 nathanw 34,
163 1.6.2.2 nathanw 35,
164 1.6.2.2 nathanw 5,
165 1.6.2.2 nathanw 5,
166 1.6.2.2 nathanw 6,
167 1.6.2.2 nathanw 7,
168 1.6.2.2 nathanw 8,
169 1.6.2.2 nathanw 9,
170 1.6.2.2 nathanw 10,
171 1.6.2.2 nathanw 11,
172 1.6.2.2 nathanw 12,
173 1.6.2.2 nathanw 13,
174 1.6.2.2 nathanw 14,
175 1.6.2.2 nathanw 15,
176 1.6.2.2 nathanw 16,
177 1.6.2.2 nathanw 17,
178 1.6.2.2 nathanw 18,
179 1.6.2.2 nathanw 19,
180 1.6.2.2 nathanw 20,
181 1.6.2.2 nathanw 21,
182 1.6.2.2 nathanw 22,
183 1.6.2.2 nathanw 23,
184 1.6.2.2 nathanw 24,
185 1.6.2.2 nathanw 25,
186 1.6.2.2 nathanw 26,
187 1.6.2.2 nathanw 27,
188 1.6.2.2 nathanw 28,
189 1.6.2.2 nathanw 29,
190 1.6.2.2 nathanw 30,
191 1.6.2.2 nathanw 31,
192 1.6.2.2 nathanw };
193 1.6.2.2 nathanw
194 1.6.2.2 nathanw /*
195 1.6.2.2 nathanw * Internal forward declarations.
196 1.6.2.2 nathanw */
197 1.6.2.2 nathanw struct asc_softc;
198 1.6.2.2 nathanw static void asc_reset __P((struct asc_softc *, asc_regmap_t *));
199 1.6.2.2 nathanw static void asc_startcmd __P((struct asc_softc *, int));
200 1.6.2.2 nathanw
201 1.6.2.2 nathanw #ifdef DEBUG
202 1.6.2.2 nathanw int asc_debug = 1;
203 1.6.2.2 nathanw int asc_debug_cmd;
204 1.6.2.2 nathanw int asc_debug_bn;
205 1.6.2.2 nathanw int asc_debug_sz;
206 1.6.2.2 nathanw #define NLOG 16
207 1.6.2.2 nathanw struct asc_log {
208 1.6.2.2 nathanw u_int status;
209 1.6.2.2 nathanw u_char state;
210 1.6.2.2 nathanw u_char msg;
211 1.6.2.2 nathanw int target;
212 1.6.2.2 nathanw int resid;
213 1.6.2.2 nathanw } asc_log[NLOG], *asc_logp = asc_log;
214 1.6.2.2 nathanw #define PACK(unit, status, ss, ir) \
215 1.6.2.2 nathanw ((unit << 24) | (status << 16) | (ss << 8) | ir)
216 1.6.2.2 nathanw #endif
217 1.6.2.2 nathanw
218 1.6.2.2 nathanw /*
219 1.6.2.2 nathanw * Scripts are entries in a state machine table.
220 1.6.2.2 nathanw * A script has four parts: a pre-condition, an action, a command to the chip,
221 1.6.2.2 nathanw * and an index into asc_scripts for the next state. The first triggers error
222 1.6.2.2 nathanw * handling if not satisfied and in our case it is formed by the
223 1.6.2.2 nathanw * values of the interrupt register and status register, this
224 1.6.2.2 nathanw * basically captures the phase of the bus and the TC and BS
225 1.6.2.2 nathanw * bits. The action part is just a function pointer, and the
226 1.6.2.2 nathanw * command is what the 53C94 should be told to do at the end
227 1.6.2.2 nathanw * of the action processing. This command is only issued and the
228 1.6.2.2 nathanw * script proceeds if the action routine returns TRUE.
229 1.6.2.2 nathanw * See asc_intr() for how and where this is all done.
230 1.6.2.2 nathanw */
231 1.6.2.2 nathanw typedef struct script {
232 1.6.2.2 nathanw int condition; /* expected state at interrupt time */
233 1.6.2.2 nathanw int (*action)(struct asc_softc *, int, int, int);
234 1.6.2.2 nathanw /* extra operations */
235 1.6.2.2 nathanw int command; /* command to the chip */
236 1.6.2.2 nathanw struct script *next; /* index into asc_scripts for next state */
237 1.6.2.2 nathanw } script_t;
238 1.6.2.2 nathanw
239 1.6.2.2 nathanw /* Matching on the condition value */
240 1.6.2.2 nathanw #define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8))
241 1.6.2.2 nathanw
242 1.6.2.2 nathanw
243 1.6.2.2 nathanw /* forward decls of script actions */
244 1.6.2.2 nathanw /* when nothing needed */
245 1.6.2.2 nathanw static int script_nop __P((struct asc_softc *, int, int, int));
246 1.6.2.2 nathanw /* all come to an end */
247 1.6.2.2 nathanw static int asc_end __P((struct asc_softc *, int, int, int));
248 1.6.2.2 nathanw /* get status from target */
249 1.6.2.2 nathanw static int asc_get_status __P((struct asc_softc *, int, int, int));
250 1.6.2.2 nathanw /* start reading data from target */
251 1.6.2.2 nathanw static int asc_dma_in __P((struct asc_softc *, int, int, int));
252 1.6.2.2 nathanw /* cleanup after all data is read */
253 1.6.2.2 nathanw static int asc_last_dma_in __P((struct asc_softc *, int, int, int));
254 1.6.2.2 nathanw /* resume data in after a message */
255 1.6.2.2 nathanw static int asc_resume_in __P((struct asc_softc *, int, int, int));
256 1.6.2.2 nathanw /* resume DMA after a disconnect */
257 1.6.2.2 nathanw static int asc_resume_dma_in __P((struct asc_softc *, int, int, int));
258 1.6.2.2 nathanw /* send data to target via dma */
259 1.6.2.2 nathanw static int asc_dma_out __P((struct asc_softc *, int, int, int));
260 1.6.2.2 nathanw /* cleanup after all data is written */
261 1.6.2.2 nathanw static int asc_last_dma_out __P((struct asc_softc *, int, int, int));
262 1.6.2.2 nathanw /* resume data out after a message */
263 1.6.2.2 nathanw static int asc_resume_out __P((struct asc_softc *, int, int, int));
264 1.6.2.2 nathanw /* resume DMA after a disconnect */
265 1.6.2.2 nathanw static int asc_resume_dma_out __P((struct asc_softc *, int, int, int));
266 1.6.2.2 nathanw /* negotiate sync xfer */
267 1.6.2.2 nathanw static int asc_sendsync __P((struct asc_softc *, int, int, int));
268 1.6.2.2 nathanw /* negotiate sync xfer */
269 1.6.2.2 nathanw static int asc_replysync __P((struct asc_softc *, int, int, int));
270 1.6.2.2 nathanw /* process a message byte */
271 1.6.2.2 nathanw static int asc_msg_in __P((struct asc_softc *, int, int, int));
272 1.6.2.2 nathanw /* process an expected disconnect */
273 1.6.2.2 nathanw static int asc_disconnect __P((struct asc_softc *, int, int, int));
274 1.6.2.2 nathanw
275 1.6.2.2 nathanw /* Define the index into asc_scripts for various state transitions */
276 1.6.2.2 nathanw #define SCRIPT_DATA_IN 0
277 1.6.2.2 nathanw #define SCRIPT_CONTINUE_IN 2
278 1.6.2.2 nathanw #define SCRIPT_DATA_OUT 3
279 1.6.2.2 nathanw #define SCRIPT_CONTINUE_OUT 5
280 1.6.2.2 nathanw #define SCRIPT_SIMPLE 6
281 1.6.2.2 nathanw #define SCRIPT_GET_STATUS 7
282 1.6.2.2 nathanw #define SCRIPT_DONE 8
283 1.6.2.2 nathanw #define SCRIPT_MSG_IN 9
284 1.6.2.2 nathanw #define SCRIPT_REPLY_SYNC 11
285 1.6.2.2 nathanw #define SCRIPT_TRY_SYNC 12
286 1.6.2.2 nathanw #define SCRIPT_DISCONNECT 15
287 1.6.2.2 nathanw #define SCRIPT_RESEL 16
288 1.6.2.2 nathanw #define SCRIPT_RESUME_IN 17
289 1.6.2.2 nathanw #define SCRIPT_RESUME_DMA_IN 18
290 1.6.2.2 nathanw #define SCRIPT_RESUME_OUT 19
291 1.6.2.2 nathanw #define SCRIPT_RESUME_DMA_OUT 20
292 1.6.2.2 nathanw #define SCRIPT_RESUME_NO_DATA 21
293 1.6.2.2 nathanw
294 1.6.2.2 nathanw /*
295 1.6.2.2 nathanw * Scripts
296 1.6.2.2 nathanw */
297 1.6.2.2 nathanw script_t asc_scripts[] = {
298 1.6.2.2 nathanw /* start data in */
299 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */
300 1.6.2.2 nathanw asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
301 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_IN + 1]},
302 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */
303 1.6.2.2 nathanw asc_last_dma_in, ASC_CMD_I_COMPLETE,
304 1.6.2.2 nathanw &asc_scripts[SCRIPT_GET_STATUS]},
305 1.6.2.2 nathanw
306 1.6.2.2 nathanw /* continue data in after a chunk is finished */
307 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */
308 1.6.2.2 nathanw asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
309 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_IN + 1]},
310 1.6.2.2 nathanw
311 1.6.2.2 nathanw /* start data out */
312 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */
313 1.6.2.2 nathanw asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
314 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_OUT + 1]},
315 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */
316 1.6.2.2 nathanw asc_last_dma_out, ASC_CMD_I_COMPLETE,
317 1.6.2.2 nathanw &asc_scripts[SCRIPT_GET_STATUS]},
318 1.6.2.2 nathanw
319 1.6.2.2 nathanw /* continue data out after a chunk is finished */
320 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */
321 1.6.2.2 nathanw asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
322 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_OUT + 1]},
323 1.6.2.2 nathanw
324 1.6.2.2 nathanw /* simple command with no data transfer */
325 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */
326 1.6.2.2 nathanw script_nop, ASC_CMD_I_COMPLETE,
327 1.6.2.2 nathanw &asc_scripts[SCRIPT_GET_STATUS]},
328 1.6.2.2 nathanw
329 1.6.2.2 nathanw /* get status and finish command */
330 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */
331 1.6.2.2 nathanw asc_get_status, ASC_CMD_MSG_ACPT,
332 1.6.2.2 nathanw &asc_scripts[SCRIPT_DONE]},
333 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */
334 1.6.2.2 nathanw asc_end, ASC_CMD_NOP,
335 1.6.2.2 nathanw &asc_scripts[SCRIPT_DONE]},
336 1.6.2.2 nathanw
337 1.6.2.2 nathanw /* message in */
338 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */
339 1.6.2.2 nathanw asc_msg_in, ASC_CMD_MSG_ACPT,
340 1.6.2.2 nathanw &asc_scripts[SCRIPT_MSG_IN + 1]},
341 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */
342 1.6.2.2 nathanw script_nop, ASC_CMD_XFER_INFO,
343 1.6.2.2 nathanw &asc_scripts[SCRIPT_MSG_IN]},
344 1.6.2.2 nathanw
345 1.6.2.2 nathanw /* send synchonous negotiation reply */
346 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */
347 1.6.2.2 nathanw asc_replysync, ASC_CMD_XFER_INFO,
348 1.6.2.2 nathanw &asc_scripts[SCRIPT_REPLY_SYNC]},
349 1.6.2.2 nathanw
350 1.6.2.2 nathanw /* try to negotiate synchonous transfer parameters */
351 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */
352 1.6.2.2 nathanw asc_sendsync, ASC_CMD_XFER_INFO,
353 1.6.2.2 nathanw &asc_scripts[SCRIPT_TRY_SYNC + 1]},
354 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */
355 1.6.2.2 nathanw script_nop, ASC_CMD_XFER_INFO,
356 1.6.2.2 nathanw &asc_scripts[SCRIPT_MSG_IN]},
357 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */
358 1.6.2.2 nathanw script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
359 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_NO_DATA]},
360 1.6.2.2 nathanw
361 1.6.2.2 nathanw /* handle a disconnect */
362 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */
363 1.6.2.2 nathanw asc_disconnect, ASC_CMD_ENABLE_SEL,
364 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESEL]},
365 1.6.2.2 nathanw
366 1.6.2.2 nathanw /* reselect sequence: this is just a placeholder so match fails */
367 1.6.2.2 nathanw {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */
368 1.6.2.2 nathanw script_nop, ASC_CMD_MSG_ACPT,
369 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESEL]},
370 1.6.2.2 nathanw
371 1.6.2.2 nathanw /* resume data in after a message */
372 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */
373 1.6.2.2 nathanw asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
374 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_IN + 1]},
375 1.6.2.2 nathanw
376 1.6.2.2 nathanw /* resume partial DMA data in after a message */
377 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */
378 1.6.2.2 nathanw asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
379 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_IN + 1]},
380 1.6.2.2 nathanw
381 1.6.2.2 nathanw /* resume data out after a message */
382 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */
383 1.6.2.2 nathanw asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
384 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_OUT + 1]},
385 1.6.2.2 nathanw
386 1.6.2.2 nathanw /* resume partial DMA data out after a message */
387 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */
388 1.6.2.2 nathanw asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
389 1.6.2.2 nathanw &asc_scripts[SCRIPT_DATA_OUT + 1]},
390 1.6.2.2 nathanw
391 1.6.2.2 nathanw /* resume after a message when there is no more data */
392 1.6.2.2 nathanw {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */
393 1.6.2.2 nathanw script_nop, ASC_CMD_I_COMPLETE,
394 1.6.2.2 nathanw &asc_scripts[SCRIPT_GET_STATUS]},
395 1.6.2.2 nathanw };
396 1.6.2.2 nathanw
397 1.6.2.2 nathanw /*
398 1.6.2.2 nathanw * State kept for each active SCSI device.
399 1.6.2.2 nathanw */
400 1.6.2.2 nathanw typedef struct scsi_state {
401 1.6.2.2 nathanw script_t *script; /* saved script while processing error */
402 1.6.2.2 nathanw struct scsi_generic cmd;/* storage for scsi command */
403 1.6.2.2 nathanw int statusByte; /* status byte returned during STATUS_PHASE */
404 1.6.2.2 nathanw u_int dmaBufSize; /* DMA buffer size */
405 1.6.2.2 nathanw int dmalen; /* amount to transfer in this chunk */
406 1.6.2.2 nathanw int dmaresid; /* amount not transfered if chunk suspended */
407 1.6.2.2 nathanw int cmdlen; /* length of command in cmd */
408 1.6.2.2 nathanw int buflen; /* total remaining amount of data to transfer */
409 1.6.2.2 nathanw vaddr_t buf; /* current pointer within scsicmd->buf */
410 1.6.2.2 nathanw int flags; /* see below */
411 1.6.2.2 nathanw int msglen; /* number of message bytes to read */
412 1.6.2.2 nathanw int msgcnt; /* number of message bytes received */
413 1.6.2.2 nathanw u_char sync_period; /* DMA synchronous period */
414 1.6.2.2 nathanw u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */
415 1.6.2.2 nathanw u_char msg_out; /* next MSG_OUT byte to send */
416 1.6.2.2 nathanw u_char msg_in[16]; /* buffer for multibyte messages */
417 1.6.2.2 nathanw } State;
418 1.6.2.2 nathanw
419 1.6.2.2 nathanw /* state flags */
420 1.6.2.2 nathanw #define DISCONN 0x001 /* true if currently disconnected from bus */
421 1.6.2.2 nathanw #define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
422 1.6.2.2 nathanw #define DMA_IN 0x004 /* true if reading from SCSI device */
423 1.6.2.2 nathanw #define DMA_OUT 0x010 /* true if writing to SCSI device */
424 1.6.2.2 nathanw #define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
425 1.6.2.2 nathanw #define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
426 1.6.2.2 nathanw #define PARITY_ERR 0x080 /* true if parity error seen */
427 1.6.2.2 nathanw
428 1.6.2.2 nathanw /*
429 1.6.2.2 nathanw * State kept for each active SCSI host interface (53C94).
430 1.6.2.2 nathanw */
431 1.6.2.2 nathanw struct asc_softc {
432 1.6.2.2 nathanw struct device sc_dev; /* use as a device */
433 1.6.2.2 nathanw asc_regmap_t *regs; /* chip address */
434 1.6.2.2 nathanw dma_softc_t __dma; /* stupid macro..... */
435 1.6.2.2 nathanw dma_softc_t *dma; /* dma control structure */
436 1.6.2.2 nathanw int sc_id; /* SCSI ID of this interface */
437 1.6.2.2 nathanw int myidmask; /* ~(1 << myid) */
438 1.6.2.2 nathanw int state; /* current SCSI connection state */
439 1.6.2.2 nathanw int target; /* target SCSI ID if busy */
440 1.6.2.2 nathanw script_t *script; /* next expected interrupt & action */
441 1.6.2.2 nathanw struct scsipi_xfer *cmdq[ASC_NCMD];/* Pointer to queued commands */
442 1.6.2.2 nathanw struct scsipi_xfer *cmd[ASC_NCMD];/* Pointer to current active command */
443 1.6.2.2 nathanw State st[ASC_NCMD]; /* state info for each active command */
444 1.6.2.2 nathanw int min_period; /* Min transfer period clk/byte */
445 1.6.2.2 nathanw int max_period; /* Max transfer period clk/byte */
446 1.6.2.2 nathanw int ccf; /* CCF, whatever that really is? */
447 1.6.2.2 nathanw int timeout_250; /* 250ms timeout */
448 1.6.2.2 nathanw int tb_ticks; /* 4ns. ticks/tb channel ticks */
449 1.6.2.2 nathanw int is24bit; /* if 53CF94/96-2, 24bit address */
450 1.6.2.2 nathanw struct scsipi_channel sc_channel;
451 1.6.2.2 nathanw struct scsipi_adapter sc_adapter;
452 1.6.2.2 nathanw };
453 1.6.2.2 nathanw
454 1.6.2.2 nathanw #define ASC_STATE_IDLE 0 /* idle state */
455 1.6.2.2 nathanw #define ASC_STATE_BUSY 1 /* selecting or currently connected */
456 1.6.2.2 nathanw #define ASC_STATE_TARGET 2 /* currently selected as target */
457 1.6.2.2 nathanw #define ASC_STATE_RESEL 3 /* currently waiting for reselect */
458 1.6.2.2 nathanw
459 1.6.2.2 nathanw typedef struct asc_softc *asc_softc_t;
460 1.6.2.2 nathanw
461 1.6.2.2 nathanw struct asc_timing {
462 1.6.2.2 nathanw int min_period; /* Min transfer period clk/byte */
463 1.6.2.2 nathanw int max_period; /* Max transfer period clk/byte */
464 1.6.2.2 nathanw int ccf; /* CCF, whatever that really is? */
465 1.6.2.2 nathanw int timeout_250; /* 250ms timeout */
466 1.6.2.2 nathanw int tb_ticks; /* 4ns. ticks/tb channel ticks */
467 1.6.2.2 nathanw } asc_timing_40mhz = {
468 1.6.2.2 nathanw ASC_MIN_PERIOD40,
469 1.6.2.2 nathanw ASC_MAX_PERIOD40,
470 1.6.2.2 nathanw ASC_CCF(40),
471 1.6.2.2 nathanw ASC_TIMEOUT_250(40, 8 /* exception for ASC_CCF(40) (== 0) */),
472 1.6.2.2 nathanw 6, /* 6.25 */
473 1.6.2.2 nathanw }, asc_timing_25mhz = {
474 1.6.2.2 nathanw ASC_MIN_PERIOD25,
475 1.6.2.2 nathanw ASC_MAX_PERIOD25,
476 1.6.2.2 nathanw ASC_CCF(25),
477 1.6.2.2 nathanw ASC_TIMEOUT_250(25, ASC_CCF(25)),
478 1.6.2.2 nathanw 10,
479 1.6.2.2 nathanw }, asc_timing_12mhz = {
480 1.6.2.2 nathanw ASC_MIN_PERIOD12,
481 1.6.2.2 nathanw ASC_MAX_PERIOD12,
482 1.6.2.2 nathanw ASC_CCF(13),
483 1.6.2.2 nathanw ASC_TIMEOUT_250(13, ASC_CCF(13)),
484 1.6.2.2 nathanw 20,
485 1.6.2.2 nathanw };
486 1.6.2.2 nathanw
487 1.6.2.2 nathanw struct asc_config *asc_conf = NULL;
488 1.6.2.2 nathanw
489 1.6.2.2 nathanw /*
490 1.6.2.2 nathanw * Autoconfiguration data for config.
491 1.6.2.2 nathanw */
492 1.6.2.2 nathanw int ascmatch __P((struct device *, struct cfdata *, void *));
493 1.6.2.2 nathanw void ascattach __P((struct device *, struct device *, void *));
494 1.6.2.2 nathanw
495 1.6.2.2 nathanw int asc_doprobe __P((void *, int, int, struct device *));
496 1.6.2.2 nathanw
497 1.6.2.2 nathanw struct cfattach asc_ca = {
498 1.6.2.2 nathanw sizeof(struct asc_softc), ascmatch, ascattach
499 1.6.2.2 nathanw };
500 1.6.2.2 nathanw
501 1.6.2.2 nathanw /*
502 1.6.2.2 nathanw * Glue to the machine dependent scsi
503 1.6.2.2 nathanw */
504 1.6.2.2 nathanw void asc_scsipi_request __P((struct scsipi_channel *,
505 1.6.2.2 nathanw scsipi_adapter_req_t, void *));
506 1.6.2.2 nathanw
507 1.6.2.2 nathanw static int asc_intr __P((void *));
508 1.6.2.2 nathanw static void asc_poll __P((struct asc_softc *, int));
509 1.6.2.2 nathanw #ifdef DEBUG
510 1.6.2.2 nathanw static void asc_DumpLog __P((char *));
511 1.6.2.2 nathanw #endif
512 1.6.2.2 nathanw
513 1.6.2.2 nathanw /*
514 1.6.2.2 nathanw * Match driver based on name
515 1.6.2.2 nathanw */
516 1.6.2.2 nathanw int
517 1.6.2.2 nathanw ascmatch(parent, match, aux)
518 1.6.2.2 nathanw struct device *parent;
519 1.6.2.2 nathanw struct cfdata *match;
520 1.6.2.2 nathanw void *aux;
521 1.6.2.2 nathanw {
522 1.6.2.2 nathanw struct jazzio_attach_args *ja = aux;
523 1.6.2.2 nathanw
524 1.6.2.2 nathanw if(strcmp(ja->ja_name, "asc") != 0)
525 1.6.2.2 nathanw return (0);
526 1.6.2.2 nathanw return (1);
527 1.6.2.2 nathanw }
528 1.6.2.2 nathanw
529 1.6.2.2 nathanw void
530 1.6.2.2 nathanw ascattach(parent, self, aux)
531 1.6.2.2 nathanw struct device *parent;
532 1.6.2.2 nathanw struct device *self;
533 1.6.2.2 nathanw void *aux;
534 1.6.2.2 nathanw {
535 1.6.2.2 nathanw struct jazzio_attach_args *ja = aux;
536 1.6.2.2 nathanw asc_softc_t asc = (void *)self;
537 1.6.2.2 nathanw asc_regmap_t *regs;
538 1.6.2.2 nathanw int id, s, i;
539 1.6.2.2 nathanw int bufsiz;
540 1.6.2.2 nathanw
541 1.6.2.2 nathanw if (asc_conf == NULL)
542 1.6.2.2 nathanw panic("asc_conf isn't initialized");
543 1.6.2.2 nathanw
544 1.6.2.2 nathanw /*
545 1.6.2.2 nathanw * Initialize hw descriptor, cache some pointers
546 1.6.2.2 nathanw */
547 1.6.2.2 nathanw asc->regs = (asc_regmap_t *)ja->ja_addr; /* XXX */
548 1.6.2.2 nathanw
549 1.6.2.2 nathanw /*
550 1.6.2.2 nathanw * Set up machine dependencies.
551 1.6.2.2 nathanw * 1) how to do dma
552 1.6.2.2 nathanw * 2) timing based on chip clock frequency
553 1.6.2.2 nathanw */
554 1.6.2.2 nathanw #if 1 /*XXX check if code handles 0 as 64k */
555 1.6.2.2 nathanw bufsiz = 63 * 1024;
556 1.6.2.2 nathanw #else
557 1.6.2.2 nathanw bufsiz = 64 * 1024;
558 1.6.2.2 nathanw #endif
559 1.6.2.2 nathanw asc->dma = &asc->__dma;
560 1.6.2.2 nathanw asc_dma_init(asc->dma);
561 1.6.2.2 nathanw
562 1.6.2.2 nathanw /*
563 1.6.2.2 nathanw * Now for timing.
564 1.6.2.2 nathanw */
565 1.6.2.2 nathanw asc->min_period = asc_conf->ac_timing->min_period;
566 1.6.2.2 nathanw asc->max_period = asc_conf->ac_timing->max_period;
567 1.6.2.2 nathanw asc->ccf = asc_conf->ac_timing->ccf;
568 1.6.2.2 nathanw asc->timeout_250 = asc_conf->ac_timing->timeout_250;
569 1.6.2.2 nathanw asc->tb_ticks = asc_conf->ac_timing->tb_ticks;
570 1.6.2.2 nathanw
571 1.6.2.2 nathanw asc->state = ASC_STATE_IDLE;
572 1.6.2.2 nathanw asc->target = -1;
573 1.6.2.2 nathanw
574 1.6.2.2 nathanw regs = asc->regs;
575 1.6.2.2 nathanw
576 1.6.2.2 nathanw /*
577 1.6.2.2 nathanw * Reset chip, fully. Note that interrupts are already enabled.
578 1.6.2.2 nathanw */
579 1.6.2.2 nathanw s = splbio();
580 1.6.2.2 nathanw
581 1.6.2.2 nathanw /* preserve our ID for now */
582 1.6.2.2 nathanw asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
583 1.6.2.2 nathanw asc->myidmask = ~(1 << asc->sc_id);
584 1.6.2.2 nathanw
585 1.6.2.2 nathanw /* identify 53CF9x-2 or not */
586 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_RESET;
587 1.6.2.2 nathanw wbflush(); DELAY(25);
588 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP;
589 1.6.2.2 nathanw wbflush(); DELAY(25);
590 1.6.2.2 nathanw regs->asc_cnfg2 = ASC_CNFG2_FE;
591 1.6.2.2 nathanw wbflush(); DELAY(25);
592 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP;
593 1.6.2.2 nathanw wbflush(); DELAY(25);
594 1.6.2.2 nathanw asc->is24bit = regs->asc_id == ASC_ID_53CF94;
595 1.6.2.2 nathanw
596 1.6.2.2 nathanw asc_reset(asc, regs);
597 1.6.2.2 nathanw
598 1.6.2.2 nathanw /*
599 1.6.2.2 nathanw * Our SCSI id on the bus.
600 1.6.2.2 nathanw * The user can set this via the prom on 3maxen/picaen.
601 1.6.2.2 nathanw * If this changes it is easy to fix: make a default that
602 1.6.2.2 nathanw * can be changed as boot arg.
603 1.6.2.2 nathanw */
604 1.6.2.2 nathanw #ifdef unneeded
605 1.6.2.2 nathanw regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
606 1.6.2.2 nathanw (scsi_initiator_id[unit] & 0x7);
607 1.6.2.2 nathanw asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
608 1.6.2.2 nathanw #endif
609 1.6.2.2 nathanw id = asc->sc_id;
610 1.6.2.2 nathanw splx(s);
611 1.6.2.2 nathanw
612 1.6.2.2 nathanw /*
613 1.6.2.2 nathanw * Give each target its DMA buffer region.
614 1.6.2.2 nathanw * The buffer address is the same for all targets,
615 1.6.2.2 nathanw * the allocated dma viritual scatter/gather space.
616 1.6.2.2 nathanw */
617 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
618 1.6.2.2 nathanw asc->st[i].dmaBufSize = bufsiz;
619 1.6.2.2 nathanw }
620 1.6.2.2 nathanw
621 1.6.2.2 nathanw /*
622 1.6.2.2 nathanw * Set up interrupt handler.
623 1.6.2.2 nathanw */
624 1.6.2.2 nathanw jazzio_intr_establish(ja->ja_intr, asc_intr, (void *)asc);
625 1.6.2.2 nathanw
626 1.6.2.2 nathanw printf(": %s, target %d\n", asc->is24bit ? "NCR53CF9X-2" : "NCR53C94",
627 1.6.2.2 nathanw id);
628 1.6.2.2 nathanw
629 1.6.2.2 nathanw asc->sc_adapter.adapt_dev = &asc->sc_dev;
630 1.6.2.2 nathanw asc->sc_adapter.adapt_nchannels = 1;
631 1.6.2.2 nathanw asc->sc_adapter.adapt_openings = 7;
632 1.6.2.2 nathanw asc->sc_adapter.adapt_max_periph = 1;
633 1.6.2.2 nathanw asc->sc_adapter.adapt_ioctl = NULL;
634 1.6.2.2 nathanw asc->sc_adapter.adapt_minphys = minphys;
635 1.6.2.2 nathanw asc->sc_adapter.adapt_request = asc_scsipi_request;
636 1.6.2.2 nathanw
637 1.6.2.2 nathanw memset(&asc->sc_channel, 0, sizeof(asc->sc_channel));
638 1.6.2.2 nathanw asc->sc_channel.chan_adapter = &asc->sc_adapter;
639 1.6.2.2 nathanw asc->sc_channel.chan_bustype = &scsi_bustype;
640 1.6.2.2 nathanw asc->sc_channel.chan_channel = 0;
641 1.6.2.2 nathanw asc->sc_channel.chan_ntargets = 8;
642 1.6.2.2 nathanw asc->sc_channel.chan_nluns = 8;
643 1.6.2.2 nathanw asc->sc_channel.chan_id = asc->sc_id;
644 1.6.2.2 nathanw
645 1.6.2.2 nathanw /*
646 1.6.2.2 nathanw * Now try to attach all the sub devices.
647 1.6.2.2 nathanw */
648 1.6.2.2 nathanw config_found(self, &asc->sc_channel, scsiprint);
649 1.6.2.2 nathanw }
650 1.6.2.2 nathanw
651 1.6.2.2 nathanw /*
652 1.6.2.2 nathanw * Start activity on a SCSI device.
653 1.6.2.2 nathanw * We maintain information on each device separately since devices can
654 1.6.2.2 nathanw * connect/disconnect during an operation.
655 1.6.2.2 nathanw */
656 1.6.2.2 nathanw void
657 1.6.2.2 nathanw asc_scsipi_request(chan, req, arg)
658 1.6.2.2 nathanw struct scsipi_channel *chan;
659 1.6.2.2 nathanw scsipi_adapter_req_t req;
660 1.6.2.2 nathanw void *arg;
661 1.6.2.2 nathanw {
662 1.6.2.2 nathanw struct scsipi_xfer *xs;
663 1.6.2.2 nathanw struct scsipi_periph *periph;
664 1.6.2.2 nathanw struct asc_softc *asc = (void *)chan->chan_adapter->adapt_dev;
665 1.6.2.2 nathanw int dontqueue, s;
666 1.6.2.2 nathanw
667 1.6.2.2 nathanw switch (req) {
668 1.6.2.2 nathanw case ADAPTER_REQ_RUN_XFER:
669 1.6.2.2 nathanw xs = arg;
670 1.6.2.2 nathanw periph = xs->xs_periph;
671 1.6.2.2 nathanw
672 1.6.2.2 nathanw dontqueue = xs->xs_control & XS_CTL_POLL;
673 1.6.2.2 nathanw
674 1.6.2.2 nathanw /*
675 1.6.2.2 nathanw * Flush caches for any data buffer
676 1.6.2.2 nathanw */
677 1.6.2.2 nathanw if(xs->datalen != 0) {
678 1.6.2.2 nathanw mips_dcache_wbinv_range((vaddr_t)xs->data, xs->datalen);
679 1.6.2.2 nathanw }
680 1.6.2.2 nathanw /*
681 1.6.2.2 nathanw * The hack on the next few lines are to avoid buffers
682 1.6.2.2 nathanw * mapped to UADDR. Realloc to the kva uarea address.
683 1.6.2.2 nathanw */
684 1.6.2.2 nathanw if((u_int)(xs->data) >= UADDR) {
685 1.6.2.2 nathanw xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curlwp->p_addr);
686 1.6.2.2 nathanw }
687 1.6.2.2 nathanw
688 1.6.2.2 nathanw s = splbio();
689 1.6.2.2 nathanw asc->cmd[periph->periph_target] = xs;
690 1.6.2.2 nathanw
691 1.6.2.2 nathanw /*
692 1.6.2.2 nathanw * Going to launch.
693 1.6.2.2 nathanw * Make a local copy of the command and some pointers.
694 1.6.2.2 nathanw */
695 1.6.2.2 nathanw asc_startcmd(asc, periph->periph_target);
696 1.6.2.2 nathanw
697 1.6.2.2 nathanw /*
698 1.6.2.2 nathanw * If in startup, interrupts not usable yet.
699 1.6.2.2 nathanw */
700 1.6.2.2 nathanw if(dontqueue) {
701 1.6.2.2 nathanw asc_poll(asc,periph->periph_target);
702 1.6.2.2 nathanw }
703 1.6.2.2 nathanw splx(s);
704 1.6.2.2 nathanw return;
705 1.6.2.2 nathanw case ADAPTER_REQ_GROW_RESOURCES:
706 1.6.2.2 nathanw /* XXX Not supported. */
707 1.6.2.2 nathanw return;
708 1.6.2.2 nathanw case ADAPTER_REQ_SET_XFER_MODE:
709 1.6.2.2 nathanw /* XXX Not supported. */
710 1.6.2.2 nathanw return;
711 1.6.2.2 nathanw }
712 1.6.2.2 nathanw }
713 1.6.2.2 nathanw
714 1.6.2.2 nathanw void
715 1.6.2.2 nathanw asc_poll(asc, target)
716 1.6.2.2 nathanw struct asc_softc *asc;
717 1.6.2.2 nathanw int target;
718 1.6.2.2 nathanw {
719 1.6.2.2 nathanw struct scsipi_xfer *scsicmd = asc->cmd[target];
720 1.6.2.2 nathanw int count = scsicmd->timeout * 10;
721 1.6.2.2 nathanw
722 1.6.2.2 nathanw while(count) {
723 1.6.2.2 nathanw if(asc->regs->asc_status &ASC_CSR_INT) {
724 1.6.2.2 nathanw asc_intr(asc);
725 1.6.2.2 nathanw }
726 1.6.2.2 nathanw if(scsicmd->xs_status & XS_STS_DONE)
727 1.6.2.2 nathanw break;
728 1.6.2.2 nathanw DELAY(5);
729 1.6.2.2 nathanw count--;
730 1.6.2.2 nathanw }
731 1.6.2.2 nathanw if(count == 0) {
732 1.6.2.2 nathanw scsicmd->error = XS_TIMEOUT;
733 1.6.2.2 nathanw asc_end(asc, 0, 0, 0);
734 1.6.2.2 nathanw }
735 1.6.2.2 nathanw }
736 1.6.2.2 nathanw
737 1.6.2.2 nathanw static void
738 1.6.2.2 nathanw asc_reset(asc, regs)
739 1.6.2.2 nathanw asc_softc_t asc;
740 1.6.2.2 nathanw asc_regmap_t *regs;
741 1.6.2.2 nathanw {
742 1.6.2.2 nathanw
743 1.6.2.2 nathanw /*
744 1.6.2.2 nathanw * Reset chip and wait till done
745 1.6.2.2 nathanw */
746 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_RESET;
747 1.6.2.2 nathanw wbflush(); DELAY(25);
748 1.6.2.2 nathanw
749 1.6.2.2 nathanw /* spec says this is needed after reset */
750 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_NOP;
751 1.6.2.2 nathanw wbflush(); DELAY(25);
752 1.6.2.2 nathanw
753 1.6.2.2 nathanw /*
754 1.6.2.2 nathanw * Set up various chip parameters
755 1.6.2.2 nathanw */
756 1.6.2.2 nathanw regs->asc_ccf = asc->ccf;
757 1.6.2.2 nathanw wbflush(); DELAY(25);
758 1.6.2.2 nathanw regs->asc_sel_timo = asc->timeout_250;
759 1.6.2.2 nathanw /* restore our ID */
760 1.6.2.2 nathanw regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK;
761 1.6.2.2 nathanw /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
762 1.6.2.2 nathanw regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
763 1.6.2.2 nathanw regs->asc_cnfg3 = asc_conf->ac_cnfg3;
764 1.6.2.2 nathanw /* zero anything else */
765 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
766 1.6.2.2 nathanw regs->asc_syn_p = asc->min_period;
767 1.6.2.2 nathanw regs->asc_syn_o = 0; /* async for now */
768 1.6.2.2 nathanw wbflush();
769 1.6.2.2 nathanw }
770 1.6.2.2 nathanw
771 1.6.2.2 nathanw /*
772 1.6.2.2 nathanw * Start a SCSI command on a target.
773 1.6.2.2 nathanw */
774 1.6.2.2 nathanw static void
775 1.6.2.2 nathanw asc_startcmd(asc, target)
776 1.6.2.2 nathanw asc_softc_t asc;
777 1.6.2.2 nathanw int target;
778 1.6.2.2 nathanw {
779 1.6.2.2 nathanw asc_regmap_t *regs;
780 1.6.2.2 nathanw State *state;
781 1.6.2.2 nathanw struct scsipi_xfer *scsicmd;
782 1.6.2.2 nathanw int i, len;
783 1.6.2.2 nathanw
784 1.6.2.2 nathanw /*
785 1.6.2.2 nathanw * See if another target is currently selected on this SCSI bus.
786 1.6.2.2 nathanw */
787 1.6.2.2 nathanw if (asc->target >= 0)
788 1.6.2.2 nathanw return;
789 1.6.2.2 nathanw
790 1.6.2.2 nathanw regs = asc->regs;
791 1.6.2.2 nathanw
792 1.6.2.2 nathanw /*
793 1.6.2.2 nathanw * If a reselection is in progress, it is Ok to ignore it since
794 1.6.2.2 nathanw * the ASC will automatically cancel the command and flush
795 1.6.2.2 nathanw * the FIFO if the ASC is reselected before the command starts.
796 1.6.2.2 nathanw * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if
797 1.6.2.2 nathanw * a reselect occurs before starting the command.
798 1.6.2.2 nathanw */
799 1.6.2.2 nathanw
800 1.6.2.2 nathanw asc->state = ASC_STATE_BUSY;
801 1.6.2.2 nathanw asc->target = target;
802 1.6.2.2 nathanw
803 1.6.2.2 nathanw /* cache some pointers */
804 1.6.2.2 nathanw scsicmd = asc->cmd[target];
805 1.6.2.2 nathanw state = &asc->st[target];
806 1.6.2.2 nathanw
807 1.6.2.2 nathanw /*
808 1.6.2.2 nathanw * Init the chip and target state.
809 1.6.2.2 nathanw */
810 1.6.2.2 nathanw state->flags = state->flags & DID_SYNC;
811 1.6.2.2 nathanw state->script = (script_t *)0;
812 1.6.2.2 nathanw state->msg_out = SCSI_NO_OP;
813 1.6.2.2 nathanw
814 1.6.2.2 nathanw /*
815 1.6.2.2 nathanw * Set up for DMA of command output. Also need to flush cache.
816 1.6.2.2 nathanw */
817 1.6.2.2 nathanw bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen);
818 1.6.2.2 nathanw state->cmdlen = scsicmd->cmdlen;
819 1.6.2.2 nathanw state->buf = (vaddr_t)scsicmd->data;
820 1.6.2.2 nathanw state->buflen = scsicmd->datalen;
821 1.6.2.2 nathanw len = state->cmdlen;
822 1.6.2.2 nathanw state->dmalen = len;
823 1.6.2.2 nathanw
824 1.6.2.2 nathanw #ifdef DEBUG
825 1.6.2.2 nathanw if (asc_debug > 1) {
826 1.6.2.2 nathanw printf("asc_startcmd: %s target %d cmd %x len %d\n",
827 1.6.2.2 nathanw asc->sc_dev.dv_xname, target,
828 1.6.2.2 nathanw state->cmd.opcode, state->buflen);
829 1.6.2.2 nathanw }
830 1.6.2.2 nathanw #endif
831 1.6.2.2 nathanw
832 1.6.2.2 nathanw /* check for simple SCSI command with no data transfer */
833 1.6.2.2 nathanw if (scsicmd->xs_control & XS_CTL_DATA_OUT) {
834 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DATA_OUT];
835 1.6.2.2 nathanw state->flags |= DMA_OUT;
836 1.6.2.2 nathanw }
837 1.6.2.2 nathanw else if (scsicmd->xs_control & XS_CTL_DATA_IN) {
838 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DATA_IN];
839 1.6.2.2 nathanw state->flags |= DMA_IN;
840 1.6.2.2 nathanw }
841 1.6.2.2 nathanw else if (state->buflen == 0) {
842 1.6.2.2 nathanw /* check for sync negotiation */
843 1.6.2.2 nathanw if ((scsicmd->xs_status & /* SCSICMD_USE_SYNC */ 0) &&
844 1.6.2.2 nathanw !(state->flags & DID_SYNC)) {
845 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
846 1.6.2.2 nathanw state->flags |= TRY_SYNC;
847 1.6.2.2 nathanw } else
848 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_SIMPLE];
849 1.6.2.2 nathanw state->buf = (vaddr_t)0;
850 1.6.2.2 nathanw }
851 1.6.2.2 nathanw
852 1.6.2.2 nathanw #ifdef DEBUG
853 1.6.2.2 nathanw asc_debug_cmd = state->cmd.opcode;
854 1.6.2.2 nathanw if (state->cmd.opcode == SCSI_READ_EXT) {
855 1.6.2.2 nathanw asc_debug_bn = (state->cmd.bytes[1] << 24) |
856 1.6.2.2 nathanw (state->cmd.bytes[2] << 16) |
857 1.6.2.2 nathanw (state->cmd.bytes[3] << 8) |
858 1.6.2.2 nathanw state->cmd.bytes[4];
859 1.6.2.2 nathanw asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7];
860 1.6.2.2 nathanw }
861 1.6.2.2 nathanw asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd);
862 1.6.2.2 nathanw asc_logp->target = asc->target;
863 1.6.2.2 nathanw asc_logp->state = asc->script - asc_scripts;
864 1.6.2.2 nathanw asc_logp->msg = SCSI_DIS_REC_IDENTIFY;
865 1.6.2.2 nathanw asc_logp->resid = scsicmd->datalen;
866 1.6.2.2 nathanw if (++asc_logp >= &asc_log[NLOG])
867 1.6.2.2 nathanw asc_logp = asc_log;
868 1.6.2.2 nathanw #endif
869 1.6.2.2 nathanw
870 1.6.2.2 nathanw /* preload the FIFO with the message and command to be sent */
871 1.6.2.2 nathanw regs->asc_fifo = SCSI_DIS_REC_IDENTIFY |
872 1.6.2.2 nathanw (scsicmd->xs_periph->periph_lun & 0x07);
873 1.6.2.2 nathanw
874 1.6.2.2 nathanw for( i = 0; i < len; i++ ) {
875 1.6.2.2 nathanw regs->asc_fifo = ((caddr_t)&state->cmd)[i];
876 1.6.2.2 nathanw }
877 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
878 1.6.2.2 nathanw readback(regs->asc_cmd);
879 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA;
880 1.6.2.2 nathanw readback(regs->asc_cmd);
881 1.6.2.2 nathanw
882 1.6.2.2 nathanw regs->asc_dbus_id = target;
883 1.6.2.2 nathanw readback(regs->asc_dbus_id);
884 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
885 1.6.2.2 nathanw readback(regs->asc_syn_p);
886 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
887 1.6.2.2 nathanw readback(regs->asc_syn_o);
888 1.6.2.2 nathanw
889 1.6.2.2 nathanw /*XXX PEFO */
890 1.6.2.2 nathanw /* we are not using sync transfer now, need to check this if we will */
891 1.6.2.2 nathanw
892 1.6.2.2 nathanw if (state->flags & TRY_SYNC)
893 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
894 1.6.2.2 nathanw else
895 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SEL_ATN;
896 1.6.2.2 nathanw readback(regs->asc_cmd);
897 1.6.2.2 nathanw }
898 1.6.2.2 nathanw
899 1.6.2.2 nathanw /*
900 1.6.2.2 nathanw * Interrupt routine
901 1.6.2.2 nathanw * Take interrupts from the chip
902 1.6.2.2 nathanw *
903 1.6.2.2 nathanw * Implementation:
904 1.6.2.2 nathanw * Move along the current command's script if
905 1.6.2.2 nathanw * all is well, invoke error handler if not.
906 1.6.2.2 nathanw */
907 1.6.2.2 nathanw int
908 1.6.2.2 nathanw asc_intr(sc)
909 1.6.2.2 nathanw void *sc;
910 1.6.2.2 nathanw {
911 1.6.2.2 nathanw asc_softc_t asc = sc;
912 1.6.2.2 nathanw asc_regmap_t *regs = asc->regs;
913 1.6.2.2 nathanw State *state;
914 1.6.2.2 nathanw script_t *scpt;
915 1.6.2.2 nathanw int ss, ir, status;
916 1.6.2.2 nathanw
917 1.6.2.2 nathanw /* collect ephemeral information */
918 1.6.2.2 nathanw status = regs->asc_status;
919 1.6.2.2 nathanw ss = regs->asc_ss;
920 1.6.2.2 nathanw
921 1.6.2.2 nathanw if ((status & ASC_CSR_INT) == 0) /* Make shure it's a real interrupt */
922 1.6.2.2 nathanw return(0);
923 1.6.2.2 nathanw
924 1.6.2.2 nathanw ir = regs->asc_intr; /* this resets the previous two */
925 1.6.2.2 nathanw scpt = asc->script;
926 1.6.2.2 nathanw
927 1.6.2.2 nathanw #ifdef DEBUG
928 1.6.2.2 nathanw asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir);
929 1.6.2.2 nathanw asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
930 1.6.2.2 nathanw asc_logp->state = scpt - asc_scripts;
931 1.6.2.2 nathanw asc_logp->msg = -1;
932 1.6.2.2 nathanw asc_logp->resid = 0;
933 1.6.2.2 nathanw if (++asc_logp >= &asc_log[NLOG])
934 1.6.2.2 nathanw asc_logp = asc_log;
935 1.6.2.2 nathanw if (asc_debug > 2)
936 1.6.2.2 nathanw printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
937 1.6.2.2 nathanw status, ss, ir, scpt - asc_scripts, scpt->condition);
938 1.6.2.2 nathanw #endif
939 1.6.2.2 nathanw
940 1.6.2.2 nathanw /* check the expected state */
941 1.6.2.2 nathanw if (SCRIPT_MATCH(ir, status) == scpt->condition) {
942 1.6.2.2 nathanw /*
943 1.6.2.2 nathanw * Perform the appropriate operation, then proceed.
944 1.6.2.2 nathanw */
945 1.6.2.2 nathanw if ((*scpt->action)(asc, status, ss, ir)) {
946 1.6.2.2 nathanw regs->asc_cmd = scpt->command;
947 1.6.2.2 nathanw readback(regs->asc_cmd);
948 1.6.2.2 nathanw asc->script = scpt->next;
949 1.6.2.2 nathanw }
950 1.6.2.2 nathanw goto done;
951 1.6.2.2 nathanw }
952 1.6.2.2 nathanw
953 1.6.2.2 nathanw /*
954 1.6.2.2 nathanw * Check for parity error.
955 1.6.2.2 nathanw * Hardware will automatically set ATN
956 1.6.2.2 nathanw * to request the device for a MSG_OUT phase.
957 1.6.2.2 nathanw */
958 1.6.2.2 nathanw if (status & ASC_CSR_PE) {
959 1.6.2.2 nathanw printf("%s: SCSI device %d: incomming parity error seen\n",
960 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
961 1.6.2.2 nathanw asc->st[asc->target].flags |= PARITY_ERR;
962 1.6.2.2 nathanw }
963 1.6.2.2 nathanw
964 1.6.2.2 nathanw /*
965 1.6.2.2 nathanw * Check for gross error.
966 1.6.2.2 nathanw * Probably a bug in a device driver.
967 1.6.2.2 nathanw */
968 1.6.2.2 nathanw if (status & ASC_CSR_GE) {
969 1.6.2.2 nathanw printf("%s: SCSI device %d: gross error\n",
970 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
971 1.6.2.2 nathanw goto abort;
972 1.6.2.2 nathanw }
973 1.6.2.2 nathanw
974 1.6.2.2 nathanw /* check for message in or out */
975 1.6.2.2 nathanw if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
976 1.6.2.2 nathanw register int len, fifo;
977 1.6.2.2 nathanw
978 1.6.2.2 nathanw state = &asc->st[asc->target];
979 1.6.2.2 nathanw switch (ASC_PHASE(status)) {
980 1.6.2.2 nathanw case ASC_PHASE_DATAI:
981 1.6.2.2 nathanw case ASC_PHASE_DATAO:
982 1.6.2.2 nathanw ASC_TC_GET(regs, len);
983 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
984 1.6.2.2 nathanw printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
985 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
986 1.6.2.2 nathanw goto abort;
987 1.6.2.2 nathanw
988 1.6.2.2 nathanw case ASC_PHASE_MSG_IN:
989 1.6.2.2 nathanw break;
990 1.6.2.2 nathanw
991 1.6.2.2 nathanw case ASC_PHASE_MSG_OUT:
992 1.6.2.2 nathanw /*
993 1.6.2.2 nathanw * Check for parity error.
994 1.6.2.2 nathanw * Hardware will automatically set ATN
995 1.6.2.2 nathanw * to request the device for a MSG_OUT phase.
996 1.6.2.2 nathanw */
997 1.6.2.2 nathanw if (state->flags & PARITY_ERR) {
998 1.6.2.2 nathanw state->flags &= ~PARITY_ERR;
999 1.6.2.2 nathanw state->msg_out = SCSI_MESSAGE_PARITY_ERROR;
1000 1.6.2.2 nathanw /* reset message in counter */
1001 1.6.2.2 nathanw state->msglen = 0;
1002 1.6.2.2 nathanw } else
1003 1.6.2.2 nathanw state->msg_out = SCSI_NO_OP;
1004 1.6.2.2 nathanw regs->asc_fifo = state->msg_out;
1005 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1006 1.6.2.2 nathanw readback(regs->asc_cmd);
1007 1.6.2.2 nathanw goto done;
1008 1.6.2.2 nathanw
1009 1.6.2.2 nathanw case ASC_PHASE_STATUS:
1010 1.6.2.2 nathanw /* probably an error in the SCSI command */
1011 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_GET_STATUS];
1012 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_I_COMPLETE;
1013 1.6.2.2 nathanw readback(regs->asc_cmd);
1014 1.6.2.2 nathanw goto done;
1015 1.6.2.2 nathanw
1016 1.6.2.2 nathanw default:
1017 1.6.2.2 nathanw goto abort;
1018 1.6.2.2 nathanw }
1019 1.6.2.2 nathanw
1020 1.6.2.2 nathanw if (state->script)
1021 1.6.2.2 nathanw goto abort;
1022 1.6.2.2 nathanw
1023 1.6.2.2 nathanw /*
1024 1.6.2.2 nathanw * OK, message coming in clean up whatever is going on.
1025 1.6.2.2 nathanw * Get number of bytes left to transfered from byte counter
1026 1.6.2.2 nathanw * counter decrements when data is trf on the SCSI bus
1027 1.6.2.2 nathanw */
1028 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1029 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1030 1.6.2.2 nathanw /* flush any data in the FIFO */
1031 1.6.2.2 nathanw if (fifo && !(state->flags & DMA_IN_PROGRESS)) {
1032 1.6.2.2 nathanw printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo);
1033 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1034 1.6.2.2 nathanw readback(regs->asc_cmd);
1035 1.6.2.2 nathanw DELAY(2);
1036 1.6.2.2 nathanw }
1037 1.6.2.2 nathanw else if (fifo && state->flags & DMA_IN_PROGRESS) {
1038 1.6.2.2 nathanw if (state->flags & DMA_OUT) {
1039 1.6.2.2 nathanw len += fifo; /* Bytes dma'ed but not sent */
1040 1.6.2.2 nathanw }
1041 1.6.2.2 nathanw else if (state->flags & DMA_IN) {
1042 1.6.2.2 nathanw printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
1043 1.6.2.2 nathanw state->dmalen, len, fifo); /* XXX */
1044 1.6.2.2 nathanw }
1045 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1046 1.6.2.2 nathanw readback(regs->asc_cmd);
1047 1.6.2.2 nathanw DELAY(2);
1048 1.6.2.2 nathanw }
1049 1.6.2.2 nathanw if (len && (state->flags & DMA_IN_PROGRESS)) {
1050 1.6.2.2 nathanw /* save number of bytes still to be sent or received */
1051 1.6.2.2 nathanw state->dmaresid = len;
1052 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1053 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
1054 1.6.2.2 nathanw #ifdef DEBUG
1055 1.6.2.2 nathanw if (asc_logp == asc_log)
1056 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1057 1.6.2.2 nathanw else
1058 1.6.2.2 nathanw asc_logp[-1].resid = len;
1059 1.6.2.2 nathanw #endif
1060 1.6.2.2 nathanw /* setup state to resume to */
1061 1.6.2.2 nathanw if (state->flags & DMA_IN) {
1062 1.6.2.2 nathanw /*
1063 1.6.2.2 nathanw * Since the ASC_CNFG3_SRB bit of the
1064 1.6.2.2 nathanw * cnfg3 register bit is not set,
1065 1.6.2.2 nathanw * we just transferred an extra byte.
1066 1.6.2.2 nathanw * Since we can't resume on an odd byte
1067 1.6.2.2 nathanw * boundary, we copy the valid data out
1068 1.6.2.2 nathanw * and resume DMA at the start address.
1069 1.6.2.2 nathanw */
1070 1.6.2.2 nathanw if (len & 1) {
1071 1.6.2.2 nathanw printf("asc_intr: msg in len %d (fifo %d)\n",
1072 1.6.2.2 nathanw len, fifo); /* XXX */
1073 1.6.2.2 nathanw len = state->dmalen - len;
1074 1.6.2.2 nathanw goto do_in;
1075 1.6.2.2 nathanw }
1076 1.6.2.2 nathanw state->script =
1077 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_DMA_IN];
1078 1.6.2.2 nathanw } else if (state->flags & DMA_OUT)
1079 1.6.2.2 nathanw state->script =
1080 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_DMA_OUT];
1081 1.6.2.2 nathanw else
1082 1.6.2.2 nathanw state->script = asc->script;
1083 1.6.2.2 nathanw } else if (state->flags & DMA_IN) {
1084 1.6.2.2 nathanw if (len) {
1085 1.6.2.2 nathanw #ifdef DEBUG
1086 1.6.2.2 nathanw printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
1087 1.6.2.2 nathanw asc_debug_bn, len, fifo); /* XXX */
1088 1.6.2.2 nathanw #endif
1089 1.6.2.2 nathanw goto abort;
1090 1.6.2.2 nathanw }
1091 1.6.2.2 nathanw /* setup state to resume to */
1092 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1093 1.6.2.2 nathanw len = state->dmalen;
1094 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1095 1.6.2.2 nathanw do_in:
1096 1.6.2.2 nathanw DMA_END(asc->dma);
1097 1.6.2.2 nathanw state->buf += len;
1098 1.6.2.2 nathanw state->buflen -= len;
1099 1.6.2.2 nathanw }
1100 1.6.2.2 nathanw if (state->buflen)
1101 1.6.2.2 nathanw state->script =
1102 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_IN];
1103 1.6.2.2 nathanw else
1104 1.6.2.2 nathanw state->script =
1105 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_NO_DATA];
1106 1.6.2.2 nathanw } else if (state->flags & DMA_OUT) {
1107 1.6.2.2 nathanw if (len) {
1108 1.6.2.2 nathanw printf("asc_intr: 2: len %d (fifo %d)\n", len,
1109 1.6.2.2 nathanw fifo); /* XXX */
1110 1.6.2.2 nathanw /* XXX THEO */
1111 1.6.2.2 nathanw #if 1
1112 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1113 1.6.2.2 nathanw readback(regs->asc_cmd);
1114 1.6.2.2 nathanw DELAY(2);
1115 1.6.2.2 nathanw len = 0;
1116 1.6.2.2 nathanw #else
1117 1.6.2.2 nathanw goto abort;
1118 1.6.2.2 nathanw #endif
1119 1.6.2.2 nathanw }
1120 1.6.2.2 nathanw /*
1121 1.6.2.2 nathanw * If this is the last chunk, the next expected
1122 1.6.2.2 nathanw * state is to get status.
1123 1.6.2.2 nathanw */
1124 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1125 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1126 1.6.2.2 nathanw DMA_END(asc->dma);
1127 1.6.2.2 nathanw len = state->dmalen;
1128 1.6.2.2 nathanw state->buf += len;
1129 1.6.2.2 nathanw state->buflen -= len;
1130 1.6.2.2 nathanw }
1131 1.6.2.2 nathanw if (state->buflen)
1132 1.6.2.2 nathanw state->script =
1133 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_OUT];
1134 1.6.2.2 nathanw else
1135 1.6.2.2 nathanw state->script =
1136 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_NO_DATA];
1137 1.6.2.2 nathanw } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
1138 1.6.2.2 nathanw state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];
1139 1.6.2.2 nathanw else
1140 1.6.2.2 nathanw state->script = asc->script;
1141 1.6.2.2 nathanw
1142 1.6.2.2 nathanw /* setup to receive a message */
1143 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_MSG_IN];
1144 1.6.2.2 nathanw state->msglen = 0;
1145 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1146 1.6.2.2 nathanw readback(regs->asc_cmd);
1147 1.6.2.2 nathanw goto done;
1148 1.6.2.2 nathanw }
1149 1.6.2.2 nathanw
1150 1.6.2.2 nathanw /* check for SCSI bus reset */
1151 1.6.2.2 nathanw if (ir & ASC_INT_RESET) {
1152 1.6.2.2 nathanw register int i;
1153 1.6.2.2 nathanw
1154 1.6.2.2 nathanw printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname);
1155 1.6.2.2 nathanw /* need to flush any pending commands */
1156 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1157 1.6.2.2 nathanw if (!asc->cmd[i])
1158 1.6.2.2 nathanw continue;
1159 1.6.2.2 nathanw asc->cmd[i]->error = XS_DRIVER_STUFFUP;
1160 1.6.2.2 nathanw asc_end(asc, 0, 0, 0);
1161 1.6.2.2 nathanw }
1162 1.6.2.2 nathanw /* rearbitrate synchronous offset */
1163 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1164 1.6.2.2 nathanw asc->st[i].sync_offset = 0;
1165 1.6.2.2 nathanw asc->st[i].flags = 0;
1166 1.6.2.2 nathanw }
1167 1.6.2.2 nathanw asc->target = -1;
1168 1.6.2.2 nathanw return(1);
1169 1.6.2.2 nathanw }
1170 1.6.2.2 nathanw
1171 1.6.2.2 nathanw /* check for command errors */
1172 1.6.2.2 nathanw if (ir & ASC_INT_ILL)
1173 1.6.2.2 nathanw goto abort;
1174 1.6.2.2 nathanw
1175 1.6.2.2 nathanw /* check for disconnect */
1176 1.6.2.2 nathanw if (ir & ASC_INT_DISC) {
1177 1.6.2.2 nathanw state = &asc->st[asc->target];
1178 1.6.2.2 nathanw switch (asc->script - asc_scripts) {
1179 1.6.2.2 nathanw case SCRIPT_DONE:
1180 1.6.2.2 nathanw case SCRIPT_DISCONNECT:
1181 1.6.2.2 nathanw /*
1182 1.6.2.2 nathanw * Disconnects can happen normally when the
1183 1.6.2.2 nathanw * command is complete with the phase being
1184 1.6.2.2 nathanw * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN.
1185 1.6.2.2 nathanw * The SCRIPT_MATCH() only checks for one phase
1186 1.6.2.2 nathanw * so we can wind up here.
1187 1.6.2.2 nathanw * Perform the appropriate operation, then proceed.
1188 1.6.2.2 nathanw */
1189 1.6.2.2 nathanw if ((*scpt->action)(asc, status, ss, ir)) {
1190 1.6.2.2 nathanw regs->asc_cmd = scpt->command;
1191 1.6.2.2 nathanw readback(regs->asc_cmd);
1192 1.6.2.2 nathanw asc->script = scpt->next;
1193 1.6.2.2 nathanw }
1194 1.6.2.2 nathanw goto done;
1195 1.6.2.2 nathanw
1196 1.6.2.2 nathanw case SCRIPT_TRY_SYNC:
1197 1.6.2.2 nathanw case SCRIPT_SIMPLE:
1198 1.6.2.2 nathanw case SCRIPT_DATA_IN:
1199 1.6.2.2 nathanw case SCRIPT_DATA_OUT: /* one of the starting scripts */
1200 1.6.2.2 nathanw if (ASC_SS(ss) == 0) {
1201 1.6.2.2 nathanw /* device did not respond */
1202 1.6.2.2 nathanw if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {
1203 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1204 1.6.2.2 nathanw readback(regs->asc_cmd);
1205 1.6.2.2 nathanw }
1206 1.6.2.2 nathanw asc->cmd[asc->target]->error = XS_SELTIMEOUT;
1207 1.6.2.2 nathanw asc_end(asc, status, ss, ir);
1208 1.6.2.2 nathanw return(1);
1209 1.6.2.2 nathanw }
1210 1.6.2.2 nathanw /* FALLTHROUGH */
1211 1.6.2.2 nathanw
1212 1.6.2.2 nathanw default:
1213 1.6.2.2 nathanw printf("%s: SCSI device %d: unexpected disconnect\n",
1214 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
1215 1.6.2.2 nathanw #ifdef DEBUG
1216 1.6.2.2 nathanw asc_DumpLog("asc_disc");
1217 1.6.2.2 nathanw #endif
1218 1.6.2.2 nathanw /*
1219 1.6.2.2 nathanw * On rare occasions my RZ24 does a disconnect during
1220 1.6.2.2 nathanw * data in phase and the following seems to keep it
1221 1.6.2.2 nathanw * happy.
1222 1.6.2.2 nathanw * XXX Should a scsi disk ever do this??
1223 1.6.2.2 nathanw */
1224 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_RESEL];
1225 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
1226 1.6.2.2 nathanw state->flags |= DISCONN;
1227 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1228 1.6.2.2 nathanw readback(regs->asc_cmd);
1229 1.6.2.2 nathanw return(1);
1230 1.6.2.2 nathanw }
1231 1.6.2.2 nathanw }
1232 1.6.2.2 nathanw
1233 1.6.2.2 nathanw /* check for reselect */
1234 1.6.2.2 nathanw if (ir & ASC_INT_RESEL) {
1235 1.6.2.2 nathanw unsigned fifo, id, msg;
1236 1.6.2.2 nathanw
1237 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1238 1.6.2.2 nathanw if (fifo < 2)
1239 1.6.2.2 nathanw goto abort;
1240 1.6.2.2 nathanw /* read unencoded SCSI ID and convert to binary */
1241 1.6.2.2 nathanw msg = regs->asc_fifo & asc->myidmask;
1242 1.6.2.2 nathanw for (id = 0; (msg & 1) == 0; id++)
1243 1.6.2.2 nathanw msg >>= 1;
1244 1.6.2.2 nathanw /* read identify message */
1245 1.6.2.2 nathanw msg = regs->asc_fifo;
1246 1.6.2.2 nathanw #ifdef DEBUG
1247 1.6.2.2 nathanw if (asc_logp == asc_log)
1248 1.6.2.2 nathanw asc_log[NLOG - 1].msg = msg;
1249 1.6.2.2 nathanw else
1250 1.6.2.2 nathanw asc_logp[-1].msg = msg;
1251 1.6.2.2 nathanw #endif
1252 1.6.2.2 nathanw asc->state = ASC_STATE_BUSY;
1253 1.6.2.2 nathanw asc->target = id;
1254 1.6.2.2 nathanw state = &asc->st[id];
1255 1.6.2.2 nathanw asc->script = state->script;
1256 1.6.2.2 nathanw state->script = (script_t *)0;
1257 1.6.2.2 nathanw if (!(state->flags & DISCONN))
1258 1.6.2.2 nathanw goto abort;
1259 1.6.2.2 nathanw state->flags &= ~DISCONN;
1260 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1261 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1262 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1263 1.6.2.2 nathanw readback(regs->asc_cmd);
1264 1.6.2.2 nathanw goto done;
1265 1.6.2.2 nathanw }
1266 1.6.2.2 nathanw
1267 1.6.2.2 nathanw /* check if we are being selected as a target */
1268 1.6.2.2 nathanw if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
1269 1.6.2.2 nathanw goto abort;
1270 1.6.2.2 nathanw
1271 1.6.2.2 nathanw /*
1272 1.6.2.2 nathanw * 'ir' must be just ASC_INT_FC.
1273 1.6.2.2 nathanw * This is normal if canceling an ASC_ENABLE_SEL.
1274 1.6.2.2 nathanw */
1275 1.6.2.2 nathanw
1276 1.6.2.2 nathanw done:
1277 1.6.2.2 nathanw wbflush();
1278 1.6.2.2 nathanw /*
1279 1.6.2.2 nathanw * If the next interrupt comes in immediatly the interrupt
1280 1.6.2.2 nathanw * dispatcher (which we are returning to) will catch it
1281 1.6.2.2 nathanw * before returning to the interrupted code.
1282 1.6.2.2 nathanw */
1283 1.6.2.2 nathanw return(1);
1284 1.6.2.2 nathanw
1285 1.6.2.2 nathanw abort:
1286 1.6.2.2 nathanw #ifdef DEBUG
1287 1.6.2.2 nathanw asc_DumpLog("asc_intr");
1288 1.6.2.2 nathanw #endif
1289 1.6.2.2 nathanw panic("asc_intr");
1290 1.6.2.2 nathanw return(1);
1291 1.6.2.2 nathanw }
1292 1.6.2.2 nathanw
1293 1.6.2.2 nathanw /*
1294 1.6.2.2 nathanw * All the many little things that the interrupt
1295 1.6.2.2 nathanw * routine might switch to.
1296 1.6.2.2 nathanw */
1297 1.6.2.2 nathanw
1298 1.6.2.2 nathanw /* ARGSUSED */
1299 1.6.2.2 nathanw static int
1300 1.6.2.2 nathanw script_nop(asc, status, ss, ir)
1301 1.6.2.2 nathanw asc_softc_t asc;
1302 1.6.2.2 nathanw int status, ss, ir;
1303 1.6.2.2 nathanw {
1304 1.6.2.2 nathanw return (1);
1305 1.6.2.2 nathanw }
1306 1.6.2.2 nathanw
1307 1.6.2.2 nathanw /* ARGSUSED */
1308 1.6.2.2 nathanw static int
1309 1.6.2.2 nathanw asc_get_status(asc, status, ss, ir)
1310 1.6.2.2 nathanw register asc_softc_t asc;
1311 1.6.2.2 nathanw register int status, ss, ir;
1312 1.6.2.2 nathanw {
1313 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1314 1.6.2.2 nathanw register int data;
1315 1.6.2.2 nathanw
1316 1.6.2.2 nathanw /*
1317 1.6.2.2 nathanw * Get the last two bytes in the FIFO.
1318 1.6.2.2 nathanw */
1319 1.6.2.2 nathanw if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
1320 1.6.2.2 nathanw printf("asc_get_status: cmdreg %x, fifo cnt %d\n",
1321 1.6.2.2 nathanw regs->asc_cmd, data); /* XXX */
1322 1.6.2.2 nathanw #ifdef DEBUG
1323 1.6.2.2 nathanw asc_DumpLog("get_status"); /* XXX */
1324 1.6.2.2 nathanw #endif
1325 1.6.2.2 nathanw if (data < 2) {
1326 1.6.2.2 nathanw asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
1327 1.6.2.2 nathanw readback(asc->regs->asc_cmd);
1328 1.6.2.2 nathanw return (0);
1329 1.6.2.2 nathanw }
1330 1.6.2.2 nathanw do {
1331 1.6.2.2 nathanw data = regs->asc_fifo;
1332 1.6.2.2 nathanw } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
1333 1.6.2.2 nathanw }
1334 1.6.2.2 nathanw
1335 1.6.2.2 nathanw /* save the status byte */
1336 1.6.2.2 nathanw asc->st[asc->target].statusByte = data = regs->asc_fifo;
1337 1.6.2.2 nathanw #ifdef DEBUG
1338 1.6.2.2 nathanw if (asc_logp == asc_log)
1339 1.6.2.2 nathanw asc_log[NLOG - 1].msg = data;
1340 1.6.2.2 nathanw else
1341 1.6.2.2 nathanw asc_logp[-1].msg = data;
1342 1.6.2.2 nathanw #endif
1343 1.6.2.2 nathanw
1344 1.6.2.2 nathanw /* get the (presumed) command_complete message */
1345 1.6.2.2 nathanw if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
1346 1.6.2.2 nathanw return (1);
1347 1.6.2.2 nathanw
1348 1.6.2.2 nathanw #ifdef DEBUG
1349 1.6.2.2 nathanw printf("asc_get_status: status %x cmd %x\n",
1350 1.6.2.2 nathanw asc->st[asc->target].statusByte, data);
1351 1.6.2.2 nathanw asc_DumpLog("asc_get_status");
1352 1.6.2.2 nathanw #endif
1353 1.6.2.2 nathanw return (0);
1354 1.6.2.2 nathanw }
1355 1.6.2.2 nathanw
1356 1.6.2.2 nathanw /* ARGSUSED */
1357 1.6.2.2 nathanw static int
1358 1.6.2.2 nathanw asc_end(asc, status, ss, ir)
1359 1.6.2.2 nathanw asc_softc_t asc;
1360 1.6.2.2 nathanw int status, ss, ir;
1361 1.6.2.2 nathanw {
1362 1.6.2.2 nathanw struct scsipi_xfer *scsicmd;
1363 1.6.2.2 nathanw struct scsipi_periph *periph;
1364 1.6.2.2 nathanw State *state;
1365 1.6.2.2 nathanw int i, target;
1366 1.6.2.2 nathanw
1367 1.6.2.2 nathanw asc->state = ASC_STATE_IDLE;
1368 1.6.2.2 nathanw target = asc->target;
1369 1.6.2.2 nathanw asc->target = -1;
1370 1.6.2.2 nathanw scsicmd = asc->cmd[target];
1371 1.6.2.2 nathanw periph = scsicmd->xs_periph;
1372 1.6.2.2 nathanw asc->cmd[target] = (struct scsipi_xfer *)0;
1373 1.6.2.2 nathanw state = &asc->st[target];
1374 1.6.2.2 nathanw
1375 1.6.2.2 nathanw #ifdef DEBUG
1376 1.6.2.2 nathanw if (asc_debug > 1) {
1377 1.6.2.2 nathanw printf("asc_end: %s target %d cmd %x err %d resid %d\n",
1378 1.6.2.2 nathanw asc->sc_dev.dv_xname, target,
1379 1.6.2.2 nathanw state->cmd.opcode, scsicmd->error, state->buflen);
1380 1.6.2.2 nathanw }
1381 1.6.2.2 nathanw #endif
1382 1.6.2.2 nathanw #ifdef DIAGNOSTIC
1383 1.6.2.2 nathanw if (target < 0 || !scsicmd)
1384 1.6.2.2 nathanw panic("asc_end");
1385 1.6.2.2 nathanw #endif
1386 1.6.2.2 nathanw
1387 1.6.2.2 nathanw /* look for disconnected devices */
1388 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1389 1.6.2.2 nathanw if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
1390 1.6.2.2 nathanw continue;
1391 1.6.2.2 nathanw asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1392 1.6.2.2 nathanw readback(asc->regs->asc_cmd);
1393 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
1394 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_RESEL];
1395 1.6.2.2 nathanw break;
1396 1.6.2.2 nathanw }
1397 1.6.2.2 nathanw
1398 1.6.2.2 nathanw if(scsicmd->error == XS_NOERROR) {
1399 1.6.2.2 nathanw if((state->statusByte & ST_MASK) == SCSI_CHECK) {
1400 1.6.2.2 nathanw scsicmd->status = state->statusByte;
1401 1.6.2.2 nathanw scsicmd->error = XS_BUSY;
1402 1.6.2.2 nathanw }
1403 1.6.2.2 nathanw }
1404 1.6.2.2 nathanw
1405 1.6.2.2 nathanw scsicmd->resid = state->buflen;
1406 1.6.2.2 nathanw
1407 1.6.2.2 nathanw /*
1408 1.6.2.2 nathanw * Look for another device that is ready.
1409 1.6.2.2 nathanw * May want to keep last one started and increment for fairness
1410 1.6.2.2 nathanw * rather than always starting at zero.
1411 1.6.2.2 nathanw */
1412 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1413 1.6.2.2 nathanw /* don't restart a disconnected command */
1414 1.6.2.2 nathanw if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
1415 1.6.2.2 nathanw continue;
1416 1.6.2.2 nathanw asc_startcmd(asc, i);
1417 1.6.2.2 nathanw break;
1418 1.6.2.2 nathanw }
1419 1.6.2.2 nathanw
1420 1.6.2.2 nathanw /* signal device driver that the command is done */
1421 1.6.2.2 nathanw scsipi_done(scsicmd);
1422 1.6.2.2 nathanw
1423 1.6.2.2 nathanw return (0);
1424 1.6.2.2 nathanw }
1425 1.6.2.2 nathanw
1426 1.6.2.2 nathanw /* ARGSUSED */
1427 1.6.2.2 nathanw static int
1428 1.6.2.2 nathanw asc_dma_in(asc, status, ss, ir)
1429 1.6.2.2 nathanw register asc_softc_t asc;
1430 1.6.2.2 nathanw register int status, ss, ir;
1431 1.6.2.2 nathanw {
1432 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1433 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1434 1.6.2.2 nathanw register int len;
1435 1.6.2.2 nathanw
1436 1.6.2.2 nathanw /* check for previous chunk in buffer */
1437 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1438 1.6.2.2 nathanw /*
1439 1.6.2.2 nathanw * Only count bytes that have been copied to memory.
1440 1.6.2.2 nathanw * There may be some bytes in the FIFO if synchonous transfers
1441 1.6.2.2 nathanw * are in progress.
1442 1.6.2.2 nathanw */
1443 1.6.2.2 nathanw DMA_END(asc->dma);
1444 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1445 1.6.2.2 nathanw len = state->dmalen - len;
1446 1.6.2.2 nathanw state->buf += len;
1447 1.6.2.2 nathanw state->buflen -= len;
1448 1.6.2.2 nathanw }
1449 1.6.2.2 nathanw
1450 1.6.2.2 nathanw /* setup to start reading the next chunk */
1451 1.6.2.2 nathanw len = state->buflen;
1452 1.6.2.2 nathanw #ifdef DEBUG
1453 1.6.2.2 nathanw if (asc_logp == asc_log)
1454 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1455 1.6.2.2 nathanw else
1456 1.6.2.2 nathanw asc_logp[-1].resid = len;
1457 1.6.2.2 nathanw #endif
1458 1.6.2.2 nathanw if (len > state->dmaBufSize)
1459 1.6.2.2 nathanw len = state->dmaBufSize;
1460 1.6.2.2 nathanw state->dmalen = len;
1461 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
1462 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1463 1.6.2.2 nathanw #ifdef DEBUG
1464 1.6.2.2 nathanw if (asc_debug > 2)
1465 1.6.2.2 nathanw printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1466 1.6.2.2 nathanw #endif
1467 1.6.2.2 nathanw
1468 1.6.2.2 nathanw /* check for next chunk */
1469 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1470 1.6.2.2 nathanw if (len != state->buflen) {
1471 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1472 1.6.2.2 nathanw readback(regs->asc_cmd);
1473 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1474 1.6.2.2 nathanw return (0);
1475 1.6.2.2 nathanw }
1476 1.6.2.2 nathanw return (1);
1477 1.6.2.2 nathanw }
1478 1.6.2.2 nathanw
1479 1.6.2.2 nathanw /* ARGSUSED */
1480 1.6.2.2 nathanw static int
1481 1.6.2.2 nathanw asc_last_dma_in(asc, status, ss, ir)
1482 1.6.2.2 nathanw register asc_softc_t asc;
1483 1.6.2.2 nathanw register int status, ss, ir;
1484 1.6.2.2 nathanw {
1485 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1486 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1487 1.6.2.2 nathanw register int len, fifo;
1488 1.6.2.2 nathanw
1489 1.6.2.2 nathanw DMA_END(asc->dma);
1490 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1491 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1492 1.6.2.2 nathanw #ifdef DEBUG
1493 1.6.2.2 nathanw if (asc_debug > 2)
1494 1.6.2.2 nathanw printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1495 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
1496 1.6.2.2 nathanw #endif
1497 1.6.2.2 nathanw if (fifo) {
1498 1.6.2.2 nathanw /* device must be trying to send more than we expect */
1499 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1500 1.6.2.2 nathanw readback(regs->asc_cmd);
1501 1.6.2.2 nathanw }
1502 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1503 1.6.2.2 nathanw len = state->dmalen - len;
1504 1.6.2.2 nathanw state->buflen -= len;
1505 1.6.2.2 nathanw
1506 1.6.2.2 nathanw return (1);
1507 1.6.2.2 nathanw }
1508 1.6.2.2 nathanw
1509 1.6.2.2 nathanw /* ARGSUSED */
1510 1.6.2.2 nathanw static int
1511 1.6.2.2 nathanw asc_resume_in(asc, status, ss, ir)
1512 1.6.2.2 nathanw register asc_softc_t asc;
1513 1.6.2.2 nathanw register int status, ss, ir;
1514 1.6.2.2 nathanw {
1515 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1516 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1517 1.6.2.2 nathanw register int len;
1518 1.6.2.2 nathanw
1519 1.6.2.2 nathanw /* setup to start reading the next chunk */
1520 1.6.2.2 nathanw len = state->buflen;
1521 1.6.2.2 nathanw #ifdef DEBUG
1522 1.6.2.2 nathanw if (asc_logp == asc_log)
1523 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1524 1.6.2.2 nathanw else
1525 1.6.2.2 nathanw asc_logp[-1].resid = len;
1526 1.6.2.2 nathanw #endif
1527 1.6.2.2 nathanw if (len > state->dmaBufSize)
1528 1.6.2.2 nathanw len = state->dmaBufSize;
1529 1.6.2.2 nathanw state->dmalen = len;
1530 1.6.2.2 nathanw #ifdef DEBUG
1531 1.6.2.2 nathanw if (asc_logp == asc_log)
1532 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1533 1.6.2.2 nathanw else
1534 1.6.2.2 nathanw asc_logp[-1].resid = len;
1535 1.6.2.2 nathanw #endif
1536 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
1537 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1538 1.6.2.2 nathanw #ifdef DEBUG
1539 1.6.2.2 nathanw if (asc_debug > 2)
1540 1.6.2.2 nathanw printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1541 1.6.2.2 nathanw len);
1542 1.6.2.2 nathanw #endif
1543 1.6.2.2 nathanw
1544 1.6.2.2 nathanw /* check for next chunk */
1545 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1546 1.6.2.2 nathanw if (len != state->buflen) {
1547 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1548 1.6.2.2 nathanw readback(regs->asc_cmd);
1549 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1550 1.6.2.2 nathanw return (0);
1551 1.6.2.2 nathanw }
1552 1.6.2.2 nathanw return (1);
1553 1.6.2.2 nathanw }
1554 1.6.2.2 nathanw
1555 1.6.2.2 nathanw /* ARGSUSED */
1556 1.6.2.2 nathanw static int
1557 1.6.2.2 nathanw asc_resume_dma_in(asc, status, ss, ir)
1558 1.6.2.2 nathanw register asc_softc_t asc;
1559 1.6.2.2 nathanw register int status, ss, ir;
1560 1.6.2.2 nathanw {
1561 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1562 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1563 1.6.2.2 nathanw register int len, off;
1564 1.6.2.2 nathanw
1565 1.6.2.2 nathanw /* setup to finish reading the current chunk */
1566 1.6.2.2 nathanw len = state->dmaresid;
1567 1.6.2.2 nathanw off = state->dmalen - len;
1568 1.6.2.2 nathanw if ((off & 1) && state->sync_offset) {
1569 1.6.2.2 nathanw printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1570 1.6.2.2 nathanw state->dmalen, len, off); /* XXX */
1571 1.6.2.2 nathanw regs->asc_res_fifo = ((u_char *)state->buf)[off];
1572 1.6.2.2 nathanw /*XXX Need to flush cache ? */
1573 1.6.2.2 nathanw }
1574 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV);
1575 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1576 1.6.2.2 nathanw #ifdef DEBUG
1577 1.6.2.2 nathanw if (asc_debug > 2)
1578 1.6.2.2 nathanw printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1579 1.6.2.2 nathanw state->dmalen, state->buflen, len, off);
1580 1.6.2.2 nathanw #endif
1581 1.6.2.2 nathanw
1582 1.6.2.2 nathanw /* check for next chunk */
1583 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1584 1.6.2.2 nathanw if (state->dmalen != state->buflen) {
1585 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1586 1.6.2.2 nathanw readback(regs->asc_cmd);
1587 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1588 1.6.2.2 nathanw return (0);
1589 1.6.2.2 nathanw }
1590 1.6.2.2 nathanw return (1);
1591 1.6.2.2 nathanw }
1592 1.6.2.2 nathanw
1593 1.6.2.2 nathanw /* ARGSUSED */
1594 1.6.2.2 nathanw static int
1595 1.6.2.2 nathanw asc_dma_out(asc, status, ss, ir)
1596 1.6.2.2 nathanw register asc_softc_t asc;
1597 1.6.2.2 nathanw register int status, ss, ir;
1598 1.6.2.2 nathanw {
1599 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1600 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1601 1.6.2.2 nathanw register int len, fifo;
1602 1.6.2.2 nathanw
1603 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1604 1.6.2.2 nathanw /* check to be sure previous chunk was finished */
1605 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1606 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1607 1.6.2.2 nathanw if (len || fifo)
1608 1.6.2.2 nathanw printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1609 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo); /* XXX */
1610 1.6.2.2 nathanw len += fifo;
1611 1.6.2.2 nathanw len = state->dmalen - len;
1612 1.6.2.2 nathanw state->buf += len;
1613 1.6.2.2 nathanw state->buflen -= len;
1614 1.6.2.2 nathanw }
1615 1.6.2.2 nathanw
1616 1.6.2.2 nathanw /* setup for this chunk */
1617 1.6.2.2 nathanw len = state->buflen;
1618 1.6.2.2 nathanw #ifdef DEBUG
1619 1.6.2.2 nathanw if (asc_logp == asc_log)
1620 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1621 1.6.2.2 nathanw else
1622 1.6.2.2 nathanw asc_logp[-1].resid = len;
1623 1.6.2.2 nathanw #endif
1624 1.6.2.2 nathanw if (len > state->dmaBufSize)
1625 1.6.2.2 nathanw len = state->dmaBufSize;
1626 1.6.2.2 nathanw state->dmalen = len;
1627 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
1628 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1629 1.6.2.2 nathanw #ifdef DEBUG
1630 1.6.2.2 nathanw if (asc_debug > 2)
1631 1.6.2.2 nathanw printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
1632 1.6.2.2 nathanw #endif
1633 1.6.2.2 nathanw
1634 1.6.2.2 nathanw /* check for next chunk */
1635 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1636 1.6.2.2 nathanw if (len != state->buflen) {
1637 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1638 1.6.2.2 nathanw readback(regs->asc_cmd);
1639 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1640 1.6.2.2 nathanw return (0);
1641 1.6.2.2 nathanw }
1642 1.6.2.2 nathanw return (1);
1643 1.6.2.2 nathanw }
1644 1.6.2.2 nathanw
1645 1.6.2.2 nathanw /* ARGSUSED */
1646 1.6.2.2 nathanw static int
1647 1.6.2.2 nathanw asc_last_dma_out(asc, status, ss, ir)
1648 1.6.2.2 nathanw register asc_softc_t asc;
1649 1.6.2.2 nathanw register int status, ss, ir;
1650 1.6.2.2 nathanw {
1651 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1652 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1653 1.6.2.2 nathanw register int len, fifo;
1654 1.6.2.2 nathanw
1655 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1656 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1657 1.6.2.2 nathanw #ifdef DEBUG
1658 1.6.2.2 nathanw if (asc_debug > 2)
1659 1.6.2.2 nathanw printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1660 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
1661 1.6.2.2 nathanw #endif
1662 1.6.2.2 nathanw if (fifo) {
1663 1.6.2.2 nathanw len += fifo;
1664 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1665 1.6.2.2 nathanw readback(regs->asc_cmd);
1666 1.6.2.2 nathanw }
1667 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1668 1.6.2.2 nathanw len = state->dmalen - len;
1669 1.6.2.2 nathanw state->buflen -= len;
1670 1.6.2.2 nathanw return (1);
1671 1.6.2.2 nathanw }
1672 1.6.2.2 nathanw
1673 1.6.2.2 nathanw /* ARGSUSED */
1674 1.6.2.2 nathanw static int
1675 1.6.2.2 nathanw asc_resume_out(asc, status, ss, ir)
1676 1.6.2.2 nathanw register asc_softc_t asc;
1677 1.6.2.2 nathanw register int status, ss, ir;
1678 1.6.2.2 nathanw {
1679 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1680 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1681 1.6.2.2 nathanw register int len;
1682 1.6.2.2 nathanw
1683 1.6.2.2 nathanw /* setup for this chunk */
1684 1.6.2.2 nathanw len = state->buflen;
1685 1.6.2.2 nathanw #ifdef DEBUG
1686 1.6.2.2 nathanw if (asc_logp == asc_log)
1687 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1688 1.6.2.2 nathanw else
1689 1.6.2.2 nathanw asc_logp[-1].resid = len;
1690 1.6.2.2 nathanw #endif
1691 1.6.2.2 nathanw if (len > state->dmaBufSize)
1692 1.6.2.2 nathanw len = state->dmaBufSize;
1693 1.6.2.2 nathanw state->dmalen = len;
1694 1.6.2.2 nathanw #ifdef DEBUG
1695 1.6.2.2 nathanw if (asc_logp == asc_log)
1696 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1697 1.6.2.2 nathanw else
1698 1.6.2.2 nathanw asc_logp[-1].resid = len;
1699 1.6.2.2 nathanw #endif
1700 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
1701 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1702 1.6.2.2 nathanw #ifdef DEBUG
1703 1.6.2.2 nathanw if (asc_debug > 2)
1704 1.6.2.2 nathanw printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1705 1.6.2.2 nathanw len);
1706 1.6.2.2 nathanw #endif
1707 1.6.2.2 nathanw
1708 1.6.2.2 nathanw /* check for next chunk */
1709 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1710 1.6.2.2 nathanw if (len != state->buflen) {
1711 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1712 1.6.2.2 nathanw readback(regs->asc_cmd);
1713 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1714 1.6.2.2 nathanw return (0);
1715 1.6.2.2 nathanw }
1716 1.6.2.2 nathanw return (1);
1717 1.6.2.2 nathanw }
1718 1.6.2.2 nathanw
1719 1.6.2.2 nathanw /* ARGSUSED */
1720 1.6.2.2 nathanw static int
1721 1.6.2.2 nathanw asc_resume_dma_out(asc, status, ss, ir)
1722 1.6.2.2 nathanw register asc_softc_t asc;
1723 1.6.2.2 nathanw register int status, ss, ir;
1724 1.6.2.2 nathanw {
1725 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1726 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1727 1.6.2.2 nathanw register int len, off;
1728 1.6.2.2 nathanw
1729 1.6.2.2 nathanw /* setup to finish writing this chunk */
1730 1.6.2.2 nathanw len = state->dmaresid;
1731 1.6.2.2 nathanw off = state->dmalen - len;
1732 1.6.2.2 nathanw if (off & 1) {
1733 1.6.2.2 nathanw printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1734 1.6.2.2 nathanw state->dmalen, len, off); /* XXX */
1735 1.6.2.2 nathanw regs->asc_fifo = ((u_char *)state->buf)[off];
1736 1.6.2.2 nathanw /*XXX Need to flush Cache ? */
1737 1.6.2.2 nathanw off++;
1738 1.6.2.2 nathanw len--;
1739 1.6.2.2 nathanw }
1740 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV);
1741 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1742 1.6.2.2 nathanw #ifdef DEBUG
1743 1.6.2.2 nathanw if (asc_debug > 2)
1744 1.6.2.2 nathanw printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1745 1.6.2.2 nathanw state->dmalen, state->buflen, len, off);
1746 1.6.2.2 nathanw #endif
1747 1.6.2.2 nathanw
1748 1.6.2.2 nathanw /* check for next chunk */
1749 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1750 1.6.2.2 nathanw if (state->dmalen != state->buflen) {
1751 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1752 1.6.2.2 nathanw readback(regs->asc_cmd);
1753 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1754 1.6.2.2 nathanw return (0);
1755 1.6.2.2 nathanw }
1756 1.6.2.2 nathanw return (1);
1757 1.6.2.2 nathanw }
1758 1.6.2.2 nathanw
1759 1.6.2.2 nathanw /* ARGSUSED */
1760 1.6.2.2 nathanw static int
1761 1.6.2.2 nathanw asc_sendsync(asc, status, ss, ir)
1762 1.6.2.2 nathanw register asc_softc_t asc;
1763 1.6.2.2 nathanw register int status, ss, ir;
1764 1.6.2.2 nathanw {
1765 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1766 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1767 1.6.2.2 nathanw
1768 1.6.2.2 nathanw /* send the extended synchronous negotiation message */
1769 1.6.2.2 nathanw regs->asc_fifo = SCSI_EXTENDED_MSG;
1770 1.6.2.2 nathanw wbflush();
1771 1.6.2.2 nathanw regs->asc_fifo = 3;
1772 1.6.2.2 nathanw wbflush();
1773 1.6.2.2 nathanw regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1774 1.6.2.2 nathanw wbflush();
1775 1.6.2.2 nathanw regs->asc_fifo = SCSI_MIN_PERIOD;
1776 1.6.2.2 nathanw wbflush();
1777 1.6.2.2 nathanw regs->asc_fifo = ASC_MAX_OFFSET;
1778 1.6.2.2 nathanw /* state to resume after we see the sync reply message */
1779 1.6.2.2 nathanw state->script = asc->script + 2;
1780 1.6.2.2 nathanw state->msglen = 0;
1781 1.6.2.2 nathanw return (1);
1782 1.6.2.2 nathanw }
1783 1.6.2.2 nathanw
1784 1.6.2.2 nathanw /* ARGSUSED */
1785 1.6.2.2 nathanw static int
1786 1.6.2.2 nathanw asc_replysync(asc, status, ss, ir)
1787 1.6.2.2 nathanw register asc_softc_t asc;
1788 1.6.2.2 nathanw register int status, ss, ir;
1789 1.6.2.2 nathanw {
1790 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1791 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1792 1.6.2.2 nathanw
1793 1.6.2.2 nathanw #ifdef DEBUG
1794 1.6.2.2 nathanw if (asc_debug > 2)
1795 1.6.2.2 nathanw printf("asc_replysync: %x %x\n",
1796 1.6.2.2 nathanw asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
1797 1.6.2.2 nathanw state->sync_offset);
1798 1.6.2.2 nathanw #endif
1799 1.6.2.2 nathanw /* send synchronous transfer in response to a request */
1800 1.6.2.2 nathanw regs->asc_fifo = SCSI_EXTENDED_MSG;
1801 1.6.2.2 nathanw wbflush();
1802 1.6.2.2 nathanw regs->asc_fifo = 3;
1803 1.6.2.2 nathanw wbflush();
1804 1.6.2.2 nathanw regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1805 1.6.2.2 nathanw wbflush();
1806 1.6.2.2 nathanw regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
1807 1.6.2.2 nathanw wbflush();
1808 1.6.2.2 nathanw regs->asc_fifo = state->sync_offset;
1809 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1810 1.6.2.2 nathanw readback(regs->asc_cmd);
1811 1.6.2.2 nathanw
1812 1.6.2.2 nathanw /* return to the appropriate script */
1813 1.6.2.2 nathanw if (!state->script) {
1814 1.6.2.2 nathanw #ifdef DEBUG
1815 1.6.2.2 nathanw asc_DumpLog("asc_replsync");
1816 1.6.2.2 nathanw #endif
1817 1.6.2.2 nathanw panic("asc_replysync");
1818 1.6.2.2 nathanw }
1819 1.6.2.2 nathanw asc->script = state->script;
1820 1.6.2.2 nathanw state->script = (script_t *)0;
1821 1.6.2.2 nathanw return (0);
1822 1.6.2.2 nathanw }
1823 1.6.2.2 nathanw
1824 1.6.2.2 nathanw /* ARGSUSED */
1825 1.6.2.2 nathanw static int
1826 1.6.2.2 nathanw asc_msg_in(asc, status, ss, ir)
1827 1.6.2.2 nathanw register asc_softc_t asc;
1828 1.6.2.2 nathanw register int status, ss, ir;
1829 1.6.2.2 nathanw {
1830 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1831 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1832 1.6.2.2 nathanw register int msg;
1833 1.6.2.2 nathanw int i;
1834 1.6.2.2 nathanw
1835 1.6.2.2 nathanw /* read one message byte */
1836 1.6.2.2 nathanw msg = regs->asc_fifo;
1837 1.6.2.2 nathanw #ifdef DEBUG
1838 1.6.2.2 nathanw if (asc_logp == asc_log)
1839 1.6.2.2 nathanw asc_log[NLOG - 1].msg = msg;
1840 1.6.2.2 nathanw else
1841 1.6.2.2 nathanw asc_logp[-1].msg = msg;
1842 1.6.2.2 nathanw #endif
1843 1.6.2.2 nathanw
1844 1.6.2.2 nathanw /* check for multi-byte message */
1845 1.6.2.2 nathanw if (state->msglen != 0) {
1846 1.6.2.2 nathanw /* first byte is the message length */
1847 1.6.2.2 nathanw if (state->msglen < 0) {
1848 1.6.2.2 nathanw state->msglen = msg;
1849 1.6.2.2 nathanw return (1);
1850 1.6.2.2 nathanw }
1851 1.6.2.2 nathanw if (state->msgcnt >= state->msglen)
1852 1.6.2.2 nathanw goto abort;
1853 1.6.2.2 nathanw state->msg_in[state->msgcnt++] = msg;
1854 1.6.2.2 nathanw
1855 1.6.2.2 nathanw /* did we just read the last byte of the message? */
1856 1.6.2.2 nathanw if (state->msgcnt != state->msglen)
1857 1.6.2.2 nathanw return (1);
1858 1.6.2.2 nathanw
1859 1.6.2.2 nathanw /* process an extended message */
1860 1.6.2.2 nathanw #ifdef DEBUG
1861 1.6.2.2 nathanw if (asc_debug > 2)
1862 1.6.2.2 nathanw printf("asc_msg_in: msg %x %x %x\n",
1863 1.6.2.2 nathanw state->msg_in[0],
1864 1.6.2.2 nathanw state->msg_in[1],
1865 1.6.2.2 nathanw state->msg_in[2]);
1866 1.6.2.2 nathanw #endif
1867 1.6.2.2 nathanw switch (state->msg_in[0]) {
1868 1.6.2.2 nathanw case SCSI_SYNCHRONOUS_XFER:
1869 1.6.2.2 nathanw state->flags |= DID_SYNC;
1870 1.6.2.2 nathanw state->sync_offset = state->msg_in[2];
1871 1.6.2.2 nathanw
1872 1.6.2.2 nathanw /* convert SCSI period to ASC period */
1873 1.6.2.2 nathanw i = state->msg_in[1] / asc->tb_ticks;
1874 1.6.2.2 nathanw if (i < asc->min_period)
1875 1.6.2.2 nathanw i = asc->min_period;
1876 1.6.2.2 nathanw else if (i >= asc->max_period) {
1877 1.6.2.2 nathanw /* can't do sync transfer, period too long */
1878 1.6.2.2 nathanw printf("%s: SCSI device %d: sync xfer period too long (%d)\n",
1879 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target, i);
1880 1.6.2.2 nathanw i = asc->max_period;
1881 1.6.2.2 nathanw state->sync_offset = 0;
1882 1.6.2.2 nathanw }
1883 1.6.2.2 nathanw if ((i * asc->tb_ticks) != state->msg_in[1])
1884 1.6.2.2 nathanw i++;
1885 1.6.2.2 nathanw state->sync_period = i & 0x1F;
1886 1.6.2.2 nathanw
1887 1.6.2.2 nathanw /*
1888 1.6.2.2 nathanw * If this is a request, check minimums and
1889 1.6.2.2 nathanw * send back an acknowledge.
1890 1.6.2.2 nathanw */
1891 1.6.2.2 nathanw if (!(state->flags & TRY_SYNC)) {
1892 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SET_ATN;
1893 1.6.2.2 nathanw readback(regs->asc_cmd);
1894 1.6.2.2 nathanw
1895 1.6.2.2 nathanw if (state->sync_period < asc->min_period)
1896 1.6.2.2 nathanw state->sync_period =
1897 1.6.2.2 nathanw asc->min_period;
1898 1.6.2.2 nathanw if (state->sync_offset > ASC_MAX_OFFSET)
1899 1.6.2.2 nathanw state->sync_offset =
1900 1.6.2.2 nathanw ASC_MAX_OFFSET;
1901 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1902 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1903 1.6.2.2 nathanw readback(regs->asc_syn_p);
1904 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1905 1.6.2.2 nathanw readback(regs->asc_syn_o);
1906 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1907 1.6.2.2 nathanw readback(regs->asc_cmd);
1908 1.6.2.2 nathanw return (0);
1909 1.6.2.2 nathanw }
1910 1.6.2.2 nathanw
1911 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1912 1.6.2.2 nathanw readback(regs->asc_syn_p);
1913 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1914 1.6.2.2 nathanw readback(regs->asc_syn_o);
1915 1.6.2.2 nathanw goto done;
1916 1.6.2.2 nathanw
1917 1.6.2.2 nathanw default:
1918 1.6.2.2 nathanw printf("%s: SCSI device %d: rejecting extended message 0x%x\n",
1919 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target,
1920 1.6.2.2 nathanw state->msg_in[0]);
1921 1.6.2.2 nathanw goto reject;
1922 1.6.2.2 nathanw }
1923 1.6.2.2 nathanw }
1924 1.6.2.2 nathanw
1925 1.6.2.2 nathanw /* process first byte of a message */
1926 1.6.2.2 nathanw #ifdef DEBUG
1927 1.6.2.2 nathanw if (asc_debug > 2)
1928 1.6.2.2 nathanw printf("asc_msg_in: msg %x\n", msg);
1929 1.6.2.2 nathanw #endif
1930 1.6.2.2 nathanw switch (msg) {
1931 1.6.2.2 nathanw #if 0
1932 1.6.2.2 nathanw case SCSI_MESSAGE_REJECT:
1933 1.6.2.2 nathanw printf(" did not like SYNCH xfer "); /* XXX */
1934 1.6.2.2 nathanw state->flags |= DID_SYNC;
1935 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1936 1.6.2.2 nathanw readback(regs->asc_cmd);
1937 1.6.2.2 nathanw status = asc_wait(regs, ASC_CSR_INT);
1938 1.6.2.2 nathanw ir = regs->asc_intr;
1939 1.6.2.2 nathanw /* some just break out here, some dont */
1940 1.6.2.2 nathanw if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1941 1.6.2.2 nathanw regs->asc_fifo = SCSI_ABORT;
1942 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1943 1.6.2.2 nathanw readback(regs->asc_cmd);
1944 1.6.2.2 nathanw status = asc_wait(regs, ASC_CSR_INT);
1945 1.6.2.2 nathanw ir = regs->asc_intr;
1946 1.6.2.2 nathanw }
1947 1.6.2.2 nathanw if (ir & ASC_INT_DISC) {
1948 1.6.2.2 nathanw asc_end(asc, status, 0, ir);
1949 1.6.2.2 nathanw return (0);
1950 1.6.2.2 nathanw }
1951 1.6.2.2 nathanw goto status;
1952 1.6.2.2 nathanw #endif /* 0 */
1953 1.6.2.2 nathanw
1954 1.6.2.2 nathanw case SCSI_EXTENDED_MSG: /* read an extended message */
1955 1.6.2.2 nathanw /* setup to read message length next */
1956 1.6.2.2 nathanw state->msglen = -1;
1957 1.6.2.2 nathanw state->msgcnt = 0;
1958 1.6.2.2 nathanw return (1);
1959 1.6.2.2 nathanw
1960 1.6.2.2 nathanw case SCSI_NO_OP:
1961 1.6.2.2 nathanw break;
1962 1.6.2.2 nathanw
1963 1.6.2.2 nathanw case SCSI_SAVE_DATA_POINTER:
1964 1.6.2.2 nathanw /* expect another message */
1965 1.6.2.2 nathanw return (1);
1966 1.6.2.2 nathanw
1967 1.6.2.2 nathanw case SCSI_RESTORE_POINTERS:
1968 1.6.2.2 nathanw /*
1969 1.6.2.2 nathanw * Need to do the following if resuming synchonous data in
1970 1.6.2.2 nathanw * on an odd byte boundary.
1971 1.6.2.2 nathanw regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1972 1.6.2.2 nathanw */
1973 1.6.2.2 nathanw break;
1974 1.6.2.2 nathanw
1975 1.6.2.2 nathanw case SCSI_DISCONNECT:
1976 1.6.2.2 nathanw if (state->flags & DISCONN)
1977 1.6.2.2 nathanw goto abort;
1978 1.6.2.2 nathanw state->flags |= DISCONN;
1979 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1980 1.6.2.2 nathanw readback(regs->asc_cmd);
1981 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1982 1.6.2.2 nathanw return (0);
1983 1.6.2.2 nathanw
1984 1.6.2.2 nathanw default:
1985 1.6.2.2 nathanw printf("%s: SCSI device %d: rejecting message 0x%x\n",
1986 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target, msg);
1987 1.6.2.2 nathanw reject:
1988 1.6.2.2 nathanw /* request a message out before acknowledging this message */
1989 1.6.2.2 nathanw state->msg_out = SCSI_MESSAGE_REJECT;
1990 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SET_ATN;
1991 1.6.2.2 nathanw readback(regs->asc_cmd);
1992 1.6.2.2 nathanw }
1993 1.6.2.2 nathanw
1994 1.6.2.2 nathanw done:
1995 1.6.2.2 nathanw /* return to original script */
1996 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1997 1.6.2.2 nathanw readback(regs->asc_cmd);
1998 1.6.2.2 nathanw if (!state->script) {
1999 1.6.2.2 nathanw abort:
2000 1.6.2.2 nathanw #ifdef DEBUG
2001 1.6.2.2 nathanw asc_DumpLog("asc_msg_in");
2002 1.6.2.2 nathanw #endif
2003 1.6.2.2 nathanw panic("asc_msg_in");
2004 1.6.2.2 nathanw }
2005 1.6.2.2 nathanw asc->script = state->script;
2006 1.6.2.2 nathanw state->script = (script_t *)0;
2007 1.6.2.2 nathanw return (0);
2008 1.6.2.2 nathanw }
2009 1.6.2.2 nathanw
2010 1.6.2.2 nathanw /* ARGSUSED */
2011 1.6.2.2 nathanw static int
2012 1.6.2.2 nathanw asc_disconnect(asc, status, ss, ir)
2013 1.6.2.2 nathanw asc_softc_t asc;
2014 1.6.2.2 nathanw int status, ss, ir;
2015 1.6.2.2 nathanw {
2016 1.6.2.2 nathanw #ifdef DIAGNOSTIC
2017 1.6.2.2 nathanw if (!(asc->st[asc->target].flags & DISCONN)) {
2018 1.6.2.2 nathanw printf("asc_disconnect: device %d: DISCONN not set!\n",
2019 1.6.2.2 nathanw asc->target);
2020 1.6.2.2 nathanw }
2021 1.6.2.2 nathanw #endif /* DIAGNOSTIC */
2022 1.6.2.2 nathanw asc->target = -1;
2023 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
2024 1.6.2.2 nathanw return (1);
2025 1.6.2.2 nathanw }
2026 1.6.2.2 nathanw
2027 1.6.2.2 nathanw #ifdef DEBUG
2028 1.6.2.2 nathanw /*
2029 1.6.2.2 nathanw * Dump the log buffer.
2030 1.6.2.2 nathanw */
2031 1.6.2.2 nathanw static void
2032 1.6.2.2 nathanw asc_DumpLog(str)
2033 1.6.2.2 nathanw char *str;
2034 1.6.2.2 nathanw {
2035 1.6.2.2 nathanw register struct asc_log *lp;
2036 1.6.2.2 nathanw register u_int status;
2037 1.6.2.2 nathanw
2038 1.6.2.2 nathanw printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
2039 1.6.2.2 nathanw asc_debug_bn, asc_debug_sz);
2040 1.6.2.2 nathanw lp = asc_logp;
2041 1.6.2.2 nathanw do {
2042 1.6.2.2 nathanw status = lp->status;
2043 1.6.2.2 nathanw printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n",
2044 1.6.2.2 nathanw status >> 24,
2045 1.6.2.2 nathanw lp->target,
2046 1.6.2.2 nathanw (status >> 16) & 0xFF,
2047 1.6.2.2 nathanw (status >> 8) & 0xFF,
2048 1.6.2.2 nathanw status & 0XFF,
2049 1.6.2.2 nathanw lp->state,
2050 1.6.2.2 nathanw asc_scripts[lp->state].condition,
2051 1.6.2.2 nathanw lp->msg, lp->resid);
2052 1.6.2.2 nathanw if (++lp >= &asc_log[NLOG])
2053 1.6.2.2 nathanw lp = asc_log;
2054 1.6.2.2 nathanw } while (lp != asc_logp);
2055 1.6.2.2 nathanw }
2056 1.6.2.2 nathanw #endif /* DEBUG */
2057