asc.c revision 1.6.2.4 1 1.6.2.4 nathanw /* $NetBSD: asc.c,v 1.6.2.4 2002/10/18 02:35:14 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.4 nathanw CFATTACH_DECL(asc, sizeof(struct asc_softc),
498 1.6.2.4 nathanw ascmatch, ascattach, NULL, NULL);
499 1.6.2.2 nathanw
500 1.6.2.2 nathanw /*
501 1.6.2.2 nathanw * Glue to the machine dependent scsi
502 1.6.2.2 nathanw */
503 1.6.2.2 nathanw void asc_scsipi_request __P((struct scsipi_channel *,
504 1.6.2.2 nathanw scsipi_adapter_req_t, void *));
505 1.6.2.2 nathanw
506 1.6.2.2 nathanw static int asc_intr __P((void *));
507 1.6.2.2 nathanw static void asc_poll __P((struct asc_softc *, int));
508 1.6.2.2 nathanw #ifdef DEBUG
509 1.6.2.2 nathanw static void asc_DumpLog __P((char *));
510 1.6.2.2 nathanw #endif
511 1.6.2.2 nathanw
512 1.6.2.2 nathanw /*
513 1.6.2.2 nathanw * Match driver based on name
514 1.6.2.2 nathanw */
515 1.6.2.2 nathanw int
516 1.6.2.2 nathanw ascmatch(parent, match, aux)
517 1.6.2.2 nathanw struct device *parent;
518 1.6.2.2 nathanw struct cfdata *match;
519 1.6.2.2 nathanw void *aux;
520 1.6.2.2 nathanw {
521 1.6.2.2 nathanw struct jazzio_attach_args *ja = aux;
522 1.6.2.2 nathanw
523 1.6.2.2 nathanw if(strcmp(ja->ja_name, "asc") != 0)
524 1.6.2.2 nathanw return (0);
525 1.6.2.2 nathanw return (1);
526 1.6.2.2 nathanw }
527 1.6.2.2 nathanw
528 1.6.2.2 nathanw void
529 1.6.2.2 nathanw ascattach(parent, self, aux)
530 1.6.2.2 nathanw struct device *parent;
531 1.6.2.2 nathanw struct device *self;
532 1.6.2.2 nathanw void *aux;
533 1.6.2.2 nathanw {
534 1.6.2.2 nathanw struct jazzio_attach_args *ja = aux;
535 1.6.2.2 nathanw asc_softc_t asc = (void *)self;
536 1.6.2.2 nathanw asc_regmap_t *regs;
537 1.6.2.2 nathanw int id, s, i;
538 1.6.2.2 nathanw int bufsiz;
539 1.6.2.2 nathanw
540 1.6.2.2 nathanw if (asc_conf == NULL)
541 1.6.2.2 nathanw panic("asc_conf isn't initialized");
542 1.6.2.2 nathanw
543 1.6.2.2 nathanw /*
544 1.6.2.2 nathanw * Initialize hw descriptor, cache some pointers
545 1.6.2.2 nathanw */
546 1.6.2.2 nathanw asc->regs = (asc_regmap_t *)ja->ja_addr; /* XXX */
547 1.6.2.2 nathanw
548 1.6.2.2 nathanw /*
549 1.6.2.2 nathanw * Set up machine dependencies.
550 1.6.2.2 nathanw * 1) how to do dma
551 1.6.2.2 nathanw * 2) timing based on chip clock frequency
552 1.6.2.2 nathanw */
553 1.6.2.2 nathanw #if 1 /*XXX check if code handles 0 as 64k */
554 1.6.2.2 nathanw bufsiz = 63 * 1024;
555 1.6.2.2 nathanw #else
556 1.6.2.2 nathanw bufsiz = 64 * 1024;
557 1.6.2.2 nathanw #endif
558 1.6.2.2 nathanw asc->dma = &asc->__dma;
559 1.6.2.2 nathanw asc_dma_init(asc->dma);
560 1.6.2.2 nathanw
561 1.6.2.2 nathanw /*
562 1.6.2.2 nathanw * Now for timing.
563 1.6.2.2 nathanw */
564 1.6.2.2 nathanw asc->min_period = asc_conf->ac_timing->min_period;
565 1.6.2.2 nathanw asc->max_period = asc_conf->ac_timing->max_period;
566 1.6.2.2 nathanw asc->ccf = asc_conf->ac_timing->ccf;
567 1.6.2.2 nathanw asc->timeout_250 = asc_conf->ac_timing->timeout_250;
568 1.6.2.2 nathanw asc->tb_ticks = asc_conf->ac_timing->tb_ticks;
569 1.6.2.2 nathanw
570 1.6.2.2 nathanw asc->state = ASC_STATE_IDLE;
571 1.6.2.2 nathanw asc->target = -1;
572 1.6.2.2 nathanw
573 1.6.2.2 nathanw regs = asc->regs;
574 1.6.2.2 nathanw
575 1.6.2.2 nathanw /*
576 1.6.2.2 nathanw * Reset chip, fully. Note that interrupts are already enabled.
577 1.6.2.2 nathanw */
578 1.6.2.2 nathanw s = splbio();
579 1.6.2.2 nathanw
580 1.6.2.2 nathanw /* preserve our ID for now */
581 1.6.2.2 nathanw asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
582 1.6.2.2 nathanw asc->myidmask = ~(1 << asc->sc_id);
583 1.6.2.2 nathanw
584 1.6.2.2 nathanw /* identify 53CF9x-2 or not */
585 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_RESET;
586 1.6.2.2 nathanw wbflush(); DELAY(25);
587 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP;
588 1.6.2.2 nathanw wbflush(); DELAY(25);
589 1.6.2.2 nathanw regs->asc_cnfg2 = ASC_CNFG2_FE;
590 1.6.2.2 nathanw wbflush(); DELAY(25);
591 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP;
592 1.6.2.2 nathanw wbflush(); DELAY(25);
593 1.6.2.2 nathanw asc->is24bit = regs->asc_id == ASC_ID_53CF94;
594 1.6.2.2 nathanw
595 1.6.2.2 nathanw asc_reset(asc, regs);
596 1.6.2.2 nathanw
597 1.6.2.2 nathanw /*
598 1.6.2.2 nathanw * Our SCSI id on the bus.
599 1.6.2.2 nathanw * The user can set this via the prom on 3maxen/picaen.
600 1.6.2.2 nathanw * If this changes it is easy to fix: make a default that
601 1.6.2.2 nathanw * can be changed as boot arg.
602 1.6.2.2 nathanw */
603 1.6.2.2 nathanw #ifdef unneeded
604 1.6.2.2 nathanw regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
605 1.6.2.2 nathanw (scsi_initiator_id[unit] & 0x7);
606 1.6.2.2 nathanw asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
607 1.6.2.2 nathanw #endif
608 1.6.2.2 nathanw id = asc->sc_id;
609 1.6.2.2 nathanw splx(s);
610 1.6.2.2 nathanw
611 1.6.2.2 nathanw /*
612 1.6.2.2 nathanw * Give each target its DMA buffer region.
613 1.6.2.2 nathanw * The buffer address is the same for all targets,
614 1.6.2.2 nathanw * the allocated dma viritual scatter/gather space.
615 1.6.2.2 nathanw */
616 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
617 1.6.2.2 nathanw asc->st[i].dmaBufSize = bufsiz;
618 1.6.2.2 nathanw }
619 1.6.2.2 nathanw
620 1.6.2.2 nathanw /*
621 1.6.2.2 nathanw * Set up interrupt handler.
622 1.6.2.2 nathanw */
623 1.6.2.2 nathanw jazzio_intr_establish(ja->ja_intr, asc_intr, (void *)asc);
624 1.6.2.2 nathanw
625 1.6.2.2 nathanw printf(": %s, target %d\n", asc->is24bit ? "NCR53CF9X-2" : "NCR53C94",
626 1.6.2.2 nathanw id);
627 1.6.2.2 nathanw
628 1.6.2.2 nathanw asc->sc_adapter.adapt_dev = &asc->sc_dev;
629 1.6.2.2 nathanw asc->sc_adapter.adapt_nchannels = 1;
630 1.6.2.2 nathanw asc->sc_adapter.adapt_openings = 7;
631 1.6.2.2 nathanw asc->sc_adapter.adapt_max_periph = 1;
632 1.6.2.2 nathanw asc->sc_adapter.adapt_ioctl = NULL;
633 1.6.2.2 nathanw asc->sc_adapter.adapt_minphys = minphys;
634 1.6.2.2 nathanw asc->sc_adapter.adapt_request = asc_scsipi_request;
635 1.6.2.2 nathanw
636 1.6.2.2 nathanw memset(&asc->sc_channel, 0, sizeof(asc->sc_channel));
637 1.6.2.2 nathanw asc->sc_channel.chan_adapter = &asc->sc_adapter;
638 1.6.2.2 nathanw asc->sc_channel.chan_bustype = &scsi_bustype;
639 1.6.2.2 nathanw asc->sc_channel.chan_channel = 0;
640 1.6.2.2 nathanw asc->sc_channel.chan_ntargets = 8;
641 1.6.2.2 nathanw asc->sc_channel.chan_nluns = 8;
642 1.6.2.2 nathanw asc->sc_channel.chan_id = asc->sc_id;
643 1.6.2.2 nathanw
644 1.6.2.2 nathanw /*
645 1.6.2.2 nathanw * Now try to attach all the sub devices.
646 1.6.2.2 nathanw */
647 1.6.2.2 nathanw config_found(self, &asc->sc_channel, scsiprint);
648 1.6.2.2 nathanw }
649 1.6.2.2 nathanw
650 1.6.2.2 nathanw /*
651 1.6.2.2 nathanw * Start activity on a SCSI device.
652 1.6.2.2 nathanw * We maintain information on each device separately since devices can
653 1.6.2.2 nathanw * connect/disconnect during an operation.
654 1.6.2.2 nathanw */
655 1.6.2.2 nathanw void
656 1.6.2.2 nathanw asc_scsipi_request(chan, req, arg)
657 1.6.2.2 nathanw struct scsipi_channel *chan;
658 1.6.2.2 nathanw scsipi_adapter_req_t req;
659 1.6.2.2 nathanw void *arg;
660 1.6.2.2 nathanw {
661 1.6.2.2 nathanw struct scsipi_xfer *xs;
662 1.6.2.2 nathanw struct scsipi_periph *periph;
663 1.6.2.2 nathanw struct asc_softc *asc = (void *)chan->chan_adapter->adapt_dev;
664 1.6.2.2 nathanw int dontqueue, s;
665 1.6.2.2 nathanw
666 1.6.2.2 nathanw switch (req) {
667 1.6.2.2 nathanw case ADAPTER_REQ_RUN_XFER:
668 1.6.2.2 nathanw xs = arg;
669 1.6.2.2 nathanw periph = xs->xs_periph;
670 1.6.2.2 nathanw
671 1.6.2.2 nathanw dontqueue = xs->xs_control & XS_CTL_POLL;
672 1.6.2.2 nathanw
673 1.6.2.2 nathanw /*
674 1.6.2.2 nathanw * Flush caches for any data buffer
675 1.6.2.2 nathanw */
676 1.6.2.2 nathanw if(xs->datalen != 0) {
677 1.6.2.2 nathanw mips_dcache_wbinv_range((vaddr_t)xs->data, xs->datalen);
678 1.6.2.2 nathanw }
679 1.6.2.2 nathanw /*
680 1.6.2.2 nathanw * The hack on the next few lines are to avoid buffers
681 1.6.2.2 nathanw * mapped to UADDR. Realloc to the kva uarea address.
682 1.6.2.2 nathanw */
683 1.6.2.2 nathanw if((u_int)(xs->data) >= UADDR) {
684 1.6.2.3 gmcgarry xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curlwp->l_addr);
685 1.6.2.2 nathanw }
686 1.6.2.2 nathanw
687 1.6.2.2 nathanw s = splbio();
688 1.6.2.2 nathanw asc->cmd[periph->periph_target] = xs;
689 1.6.2.2 nathanw
690 1.6.2.2 nathanw /*
691 1.6.2.2 nathanw * Going to launch.
692 1.6.2.2 nathanw * Make a local copy of the command and some pointers.
693 1.6.2.2 nathanw */
694 1.6.2.2 nathanw asc_startcmd(asc, periph->periph_target);
695 1.6.2.2 nathanw
696 1.6.2.2 nathanw /*
697 1.6.2.2 nathanw * If in startup, interrupts not usable yet.
698 1.6.2.2 nathanw */
699 1.6.2.2 nathanw if(dontqueue) {
700 1.6.2.2 nathanw asc_poll(asc,periph->periph_target);
701 1.6.2.2 nathanw }
702 1.6.2.2 nathanw splx(s);
703 1.6.2.2 nathanw return;
704 1.6.2.2 nathanw case ADAPTER_REQ_GROW_RESOURCES:
705 1.6.2.2 nathanw /* XXX Not supported. */
706 1.6.2.2 nathanw return;
707 1.6.2.2 nathanw case ADAPTER_REQ_SET_XFER_MODE:
708 1.6.2.2 nathanw /* XXX Not supported. */
709 1.6.2.2 nathanw return;
710 1.6.2.2 nathanw }
711 1.6.2.2 nathanw }
712 1.6.2.2 nathanw
713 1.6.2.2 nathanw void
714 1.6.2.2 nathanw asc_poll(asc, target)
715 1.6.2.2 nathanw struct asc_softc *asc;
716 1.6.2.2 nathanw int target;
717 1.6.2.2 nathanw {
718 1.6.2.2 nathanw struct scsipi_xfer *scsicmd = asc->cmd[target];
719 1.6.2.2 nathanw int count = scsicmd->timeout * 10;
720 1.6.2.2 nathanw
721 1.6.2.2 nathanw while(count) {
722 1.6.2.2 nathanw if(asc->regs->asc_status &ASC_CSR_INT) {
723 1.6.2.2 nathanw asc_intr(asc);
724 1.6.2.2 nathanw }
725 1.6.2.2 nathanw if(scsicmd->xs_status & XS_STS_DONE)
726 1.6.2.2 nathanw break;
727 1.6.2.2 nathanw DELAY(5);
728 1.6.2.2 nathanw count--;
729 1.6.2.2 nathanw }
730 1.6.2.2 nathanw if(count == 0) {
731 1.6.2.2 nathanw scsicmd->error = XS_TIMEOUT;
732 1.6.2.2 nathanw asc_end(asc, 0, 0, 0);
733 1.6.2.2 nathanw }
734 1.6.2.2 nathanw }
735 1.6.2.2 nathanw
736 1.6.2.2 nathanw static void
737 1.6.2.2 nathanw asc_reset(asc, regs)
738 1.6.2.2 nathanw asc_softc_t asc;
739 1.6.2.2 nathanw asc_regmap_t *regs;
740 1.6.2.2 nathanw {
741 1.6.2.2 nathanw
742 1.6.2.2 nathanw /*
743 1.6.2.2 nathanw * Reset chip and wait till done
744 1.6.2.2 nathanw */
745 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_RESET;
746 1.6.2.2 nathanw wbflush(); DELAY(25);
747 1.6.2.2 nathanw
748 1.6.2.2 nathanw /* spec says this is needed after reset */
749 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_NOP;
750 1.6.2.2 nathanw wbflush(); DELAY(25);
751 1.6.2.2 nathanw
752 1.6.2.2 nathanw /*
753 1.6.2.2 nathanw * Set up various chip parameters
754 1.6.2.2 nathanw */
755 1.6.2.2 nathanw regs->asc_ccf = asc->ccf;
756 1.6.2.2 nathanw wbflush(); DELAY(25);
757 1.6.2.2 nathanw regs->asc_sel_timo = asc->timeout_250;
758 1.6.2.2 nathanw /* restore our ID */
759 1.6.2.2 nathanw regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK;
760 1.6.2.2 nathanw /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
761 1.6.2.2 nathanw regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
762 1.6.2.2 nathanw regs->asc_cnfg3 = asc_conf->ac_cnfg3;
763 1.6.2.2 nathanw /* zero anything else */
764 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
765 1.6.2.2 nathanw regs->asc_syn_p = asc->min_period;
766 1.6.2.2 nathanw regs->asc_syn_o = 0; /* async for now */
767 1.6.2.2 nathanw wbflush();
768 1.6.2.2 nathanw }
769 1.6.2.2 nathanw
770 1.6.2.2 nathanw /*
771 1.6.2.2 nathanw * Start a SCSI command on a target.
772 1.6.2.2 nathanw */
773 1.6.2.2 nathanw static void
774 1.6.2.2 nathanw asc_startcmd(asc, target)
775 1.6.2.2 nathanw asc_softc_t asc;
776 1.6.2.2 nathanw int target;
777 1.6.2.2 nathanw {
778 1.6.2.2 nathanw asc_regmap_t *regs;
779 1.6.2.2 nathanw State *state;
780 1.6.2.2 nathanw struct scsipi_xfer *scsicmd;
781 1.6.2.2 nathanw int i, len;
782 1.6.2.2 nathanw
783 1.6.2.2 nathanw /*
784 1.6.2.2 nathanw * See if another target is currently selected on this SCSI bus.
785 1.6.2.2 nathanw */
786 1.6.2.2 nathanw if (asc->target >= 0)
787 1.6.2.2 nathanw return;
788 1.6.2.2 nathanw
789 1.6.2.2 nathanw regs = asc->regs;
790 1.6.2.2 nathanw
791 1.6.2.2 nathanw /*
792 1.6.2.2 nathanw * If a reselection is in progress, it is Ok to ignore it since
793 1.6.2.2 nathanw * the ASC will automatically cancel the command and flush
794 1.6.2.2 nathanw * the FIFO if the ASC is reselected before the command starts.
795 1.6.2.2 nathanw * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if
796 1.6.2.2 nathanw * a reselect occurs before starting the command.
797 1.6.2.2 nathanw */
798 1.6.2.2 nathanw
799 1.6.2.2 nathanw asc->state = ASC_STATE_BUSY;
800 1.6.2.2 nathanw asc->target = target;
801 1.6.2.2 nathanw
802 1.6.2.2 nathanw /* cache some pointers */
803 1.6.2.2 nathanw scsicmd = asc->cmd[target];
804 1.6.2.2 nathanw state = &asc->st[target];
805 1.6.2.2 nathanw
806 1.6.2.2 nathanw /*
807 1.6.2.2 nathanw * Init the chip and target state.
808 1.6.2.2 nathanw */
809 1.6.2.2 nathanw state->flags = state->flags & DID_SYNC;
810 1.6.2.2 nathanw state->script = (script_t *)0;
811 1.6.2.2 nathanw state->msg_out = SCSI_NO_OP;
812 1.6.2.2 nathanw
813 1.6.2.2 nathanw /*
814 1.6.2.2 nathanw * Set up for DMA of command output. Also need to flush cache.
815 1.6.2.2 nathanw */
816 1.6.2.2 nathanw bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen);
817 1.6.2.2 nathanw state->cmdlen = scsicmd->cmdlen;
818 1.6.2.2 nathanw state->buf = (vaddr_t)scsicmd->data;
819 1.6.2.2 nathanw state->buflen = scsicmd->datalen;
820 1.6.2.2 nathanw len = state->cmdlen;
821 1.6.2.2 nathanw state->dmalen = len;
822 1.6.2.2 nathanw
823 1.6.2.2 nathanw #ifdef DEBUG
824 1.6.2.2 nathanw if (asc_debug > 1) {
825 1.6.2.2 nathanw printf("asc_startcmd: %s target %d cmd %x len %d\n",
826 1.6.2.2 nathanw asc->sc_dev.dv_xname, target,
827 1.6.2.2 nathanw state->cmd.opcode, state->buflen);
828 1.6.2.2 nathanw }
829 1.6.2.2 nathanw #endif
830 1.6.2.2 nathanw
831 1.6.2.2 nathanw /* check for simple SCSI command with no data transfer */
832 1.6.2.2 nathanw if (scsicmd->xs_control & XS_CTL_DATA_OUT) {
833 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DATA_OUT];
834 1.6.2.2 nathanw state->flags |= DMA_OUT;
835 1.6.2.2 nathanw }
836 1.6.2.2 nathanw else if (scsicmd->xs_control & XS_CTL_DATA_IN) {
837 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DATA_IN];
838 1.6.2.2 nathanw state->flags |= DMA_IN;
839 1.6.2.2 nathanw }
840 1.6.2.2 nathanw else if (state->buflen == 0) {
841 1.6.2.2 nathanw /* check for sync negotiation */
842 1.6.2.2 nathanw if ((scsicmd->xs_status & /* SCSICMD_USE_SYNC */ 0) &&
843 1.6.2.2 nathanw !(state->flags & DID_SYNC)) {
844 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
845 1.6.2.2 nathanw state->flags |= TRY_SYNC;
846 1.6.2.2 nathanw } else
847 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_SIMPLE];
848 1.6.2.2 nathanw state->buf = (vaddr_t)0;
849 1.6.2.2 nathanw }
850 1.6.2.2 nathanw
851 1.6.2.2 nathanw #ifdef DEBUG
852 1.6.2.2 nathanw asc_debug_cmd = state->cmd.opcode;
853 1.6.2.2 nathanw if (state->cmd.opcode == SCSI_READ_EXT) {
854 1.6.2.2 nathanw asc_debug_bn = (state->cmd.bytes[1] << 24) |
855 1.6.2.2 nathanw (state->cmd.bytes[2] << 16) |
856 1.6.2.2 nathanw (state->cmd.bytes[3] << 8) |
857 1.6.2.2 nathanw state->cmd.bytes[4];
858 1.6.2.2 nathanw asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7];
859 1.6.2.2 nathanw }
860 1.6.2.2 nathanw asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd);
861 1.6.2.2 nathanw asc_logp->target = asc->target;
862 1.6.2.2 nathanw asc_logp->state = asc->script - asc_scripts;
863 1.6.2.2 nathanw asc_logp->msg = SCSI_DIS_REC_IDENTIFY;
864 1.6.2.2 nathanw asc_logp->resid = scsicmd->datalen;
865 1.6.2.2 nathanw if (++asc_logp >= &asc_log[NLOG])
866 1.6.2.2 nathanw asc_logp = asc_log;
867 1.6.2.2 nathanw #endif
868 1.6.2.2 nathanw
869 1.6.2.2 nathanw /* preload the FIFO with the message and command to be sent */
870 1.6.2.2 nathanw regs->asc_fifo = SCSI_DIS_REC_IDENTIFY |
871 1.6.2.2 nathanw (scsicmd->xs_periph->periph_lun & 0x07);
872 1.6.2.2 nathanw
873 1.6.2.2 nathanw for( i = 0; i < len; i++ ) {
874 1.6.2.2 nathanw regs->asc_fifo = ((caddr_t)&state->cmd)[i];
875 1.6.2.2 nathanw }
876 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
877 1.6.2.2 nathanw readback(regs->asc_cmd);
878 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_DMA;
879 1.6.2.2 nathanw readback(regs->asc_cmd);
880 1.6.2.2 nathanw
881 1.6.2.2 nathanw regs->asc_dbus_id = target;
882 1.6.2.2 nathanw readback(regs->asc_dbus_id);
883 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
884 1.6.2.2 nathanw readback(regs->asc_syn_p);
885 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
886 1.6.2.2 nathanw readback(regs->asc_syn_o);
887 1.6.2.2 nathanw
888 1.6.2.2 nathanw /*XXX PEFO */
889 1.6.2.2 nathanw /* we are not using sync transfer now, need to check this if we will */
890 1.6.2.2 nathanw
891 1.6.2.2 nathanw if (state->flags & TRY_SYNC)
892 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
893 1.6.2.2 nathanw else
894 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SEL_ATN;
895 1.6.2.2 nathanw readback(regs->asc_cmd);
896 1.6.2.2 nathanw }
897 1.6.2.2 nathanw
898 1.6.2.2 nathanw /*
899 1.6.2.2 nathanw * Interrupt routine
900 1.6.2.2 nathanw * Take interrupts from the chip
901 1.6.2.2 nathanw *
902 1.6.2.2 nathanw * Implementation:
903 1.6.2.2 nathanw * Move along the current command's script if
904 1.6.2.2 nathanw * all is well, invoke error handler if not.
905 1.6.2.2 nathanw */
906 1.6.2.2 nathanw int
907 1.6.2.2 nathanw asc_intr(sc)
908 1.6.2.2 nathanw void *sc;
909 1.6.2.2 nathanw {
910 1.6.2.2 nathanw asc_softc_t asc = sc;
911 1.6.2.2 nathanw asc_regmap_t *regs = asc->regs;
912 1.6.2.2 nathanw State *state;
913 1.6.2.2 nathanw script_t *scpt;
914 1.6.2.2 nathanw int ss, ir, status;
915 1.6.2.2 nathanw
916 1.6.2.2 nathanw /* collect ephemeral information */
917 1.6.2.2 nathanw status = regs->asc_status;
918 1.6.2.2 nathanw ss = regs->asc_ss;
919 1.6.2.2 nathanw
920 1.6.2.2 nathanw if ((status & ASC_CSR_INT) == 0) /* Make shure it's a real interrupt */
921 1.6.2.2 nathanw return(0);
922 1.6.2.2 nathanw
923 1.6.2.2 nathanw ir = regs->asc_intr; /* this resets the previous two */
924 1.6.2.2 nathanw scpt = asc->script;
925 1.6.2.2 nathanw
926 1.6.2.2 nathanw #ifdef DEBUG
927 1.6.2.2 nathanw asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir);
928 1.6.2.2 nathanw asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
929 1.6.2.2 nathanw asc_logp->state = scpt - asc_scripts;
930 1.6.2.2 nathanw asc_logp->msg = -1;
931 1.6.2.2 nathanw asc_logp->resid = 0;
932 1.6.2.2 nathanw if (++asc_logp >= &asc_log[NLOG])
933 1.6.2.2 nathanw asc_logp = asc_log;
934 1.6.2.2 nathanw if (asc_debug > 2)
935 1.6.2.2 nathanw printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
936 1.6.2.2 nathanw status, ss, ir, scpt - asc_scripts, scpt->condition);
937 1.6.2.2 nathanw #endif
938 1.6.2.2 nathanw
939 1.6.2.2 nathanw /* check the expected state */
940 1.6.2.2 nathanw if (SCRIPT_MATCH(ir, status) == scpt->condition) {
941 1.6.2.2 nathanw /*
942 1.6.2.2 nathanw * Perform the appropriate operation, then proceed.
943 1.6.2.2 nathanw */
944 1.6.2.2 nathanw if ((*scpt->action)(asc, status, ss, ir)) {
945 1.6.2.2 nathanw regs->asc_cmd = scpt->command;
946 1.6.2.2 nathanw readback(regs->asc_cmd);
947 1.6.2.2 nathanw asc->script = scpt->next;
948 1.6.2.2 nathanw }
949 1.6.2.2 nathanw goto done;
950 1.6.2.2 nathanw }
951 1.6.2.2 nathanw
952 1.6.2.2 nathanw /*
953 1.6.2.2 nathanw * Check for parity error.
954 1.6.2.2 nathanw * Hardware will automatically set ATN
955 1.6.2.2 nathanw * to request the device for a MSG_OUT phase.
956 1.6.2.2 nathanw */
957 1.6.2.2 nathanw if (status & ASC_CSR_PE) {
958 1.6.2.2 nathanw printf("%s: SCSI device %d: incomming parity error seen\n",
959 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
960 1.6.2.2 nathanw asc->st[asc->target].flags |= PARITY_ERR;
961 1.6.2.2 nathanw }
962 1.6.2.2 nathanw
963 1.6.2.2 nathanw /*
964 1.6.2.2 nathanw * Check for gross error.
965 1.6.2.2 nathanw * Probably a bug in a device driver.
966 1.6.2.2 nathanw */
967 1.6.2.2 nathanw if (status & ASC_CSR_GE) {
968 1.6.2.2 nathanw printf("%s: SCSI device %d: gross error\n",
969 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
970 1.6.2.2 nathanw goto abort;
971 1.6.2.2 nathanw }
972 1.6.2.2 nathanw
973 1.6.2.2 nathanw /* check for message in or out */
974 1.6.2.2 nathanw if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
975 1.6.2.2 nathanw register int len, fifo;
976 1.6.2.2 nathanw
977 1.6.2.2 nathanw state = &asc->st[asc->target];
978 1.6.2.2 nathanw switch (ASC_PHASE(status)) {
979 1.6.2.2 nathanw case ASC_PHASE_DATAI:
980 1.6.2.2 nathanw case ASC_PHASE_DATAO:
981 1.6.2.2 nathanw ASC_TC_GET(regs, len);
982 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
983 1.6.2.2 nathanw printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
984 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
985 1.6.2.2 nathanw goto abort;
986 1.6.2.2 nathanw
987 1.6.2.2 nathanw case ASC_PHASE_MSG_IN:
988 1.6.2.2 nathanw break;
989 1.6.2.2 nathanw
990 1.6.2.2 nathanw case ASC_PHASE_MSG_OUT:
991 1.6.2.2 nathanw /*
992 1.6.2.2 nathanw * Check for parity error.
993 1.6.2.2 nathanw * Hardware will automatically set ATN
994 1.6.2.2 nathanw * to request the device for a MSG_OUT phase.
995 1.6.2.2 nathanw */
996 1.6.2.2 nathanw if (state->flags & PARITY_ERR) {
997 1.6.2.2 nathanw state->flags &= ~PARITY_ERR;
998 1.6.2.2 nathanw state->msg_out = SCSI_MESSAGE_PARITY_ERROR;
999 1.6.2.2 nathanw /* reset message in counter */
1000 1.6.2.2 nathanw state->msglen = 0;
1001 1.6.2.2 nathanw } else
1002 1.6.2.2 nathanw state->msg_out = SCSI_NO_OP;
1003 1.6.2.2 nathanw regs->asc_fifo = state->msg_out;
1004 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1005 1.6.2.2 nathanw readback(regs->asc_cmd);
1006 1.6.2.2 nathanw goto done;
1007 1.6.2.2 nathanw
1008 1.6.2.2 nathanw case ASC_PHASE_STATUS:
1009 1.6.2.2 nathanw /* probably an error in the SCSI command */
1010 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_GET_STATUS];
1011 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_I_COMPLETE;
1012 1.6.2.2 nathanw readback(regs->asc_cmd);
1013 1.6.2.2 nathanw goto done;
1014 1.6.2.2 nathanw
1015 1.6.2.2 nathanw default:
1016 1.6.2.2 nathanw goto abort;
1017 1.6.2.2 nathanw }
1018 1.6.2.2 nathanw
1019 1.6.2.2 nathanw if (state->script)
1020 1.6.2.2 nathanw goto abort;
1021 1.6.2.2 nathanw
1022 1.6.2.2 nathanw /*
1023 1.6.2.2 nathanw * OK, message coming in clean up whatever is going on.
1024 1.6.2.2 nathanw * Get number of bytes left to transfered from byte counter
1025 1.6.2.2 nathanw * counter decrements when data is trf on the SCSI bus
1026 1.6.2.2 nathanw */
1027 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1028 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1029 1.6.2.2 nathanw /* flush any data in the FIFO */
1030 1.6.2.2 nathanw if (fifo && !(state->flags & DMA_IN_PROGRESS)) {
1031 1.6.2.2 nathanw printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo);
1032 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1033 1.6.2.2 nathanw readback(regs->asc_cmd);
1034 1.6.2.2 nathanw DELAY(2);
1035 1.6.2.2 nathanw }
1036 1.6.2.2 nathanw else if (fifo && state->flags & DMA_IN_PROGRESS) {
1037 1.6.2.2 nathanw if (state->flags & DMA_OUT) {
1038 1.6.2.2 nathanw len += fifo; /* Bytes dma'ed but not sent */
1039 1.6.2.2 nathanw }
1040 1.6.2.2 nathanw else if (state->flags & DMA_IN) {
1041 1.6.2.2 nathanw printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
1042 1.6.2.2 nathanw state->dmalen, len, fifo); /* XXX */
1043 1.6.2.2 nathanw }
1044 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1045 1.6.2.2 nathanw readback(regs->asc_cmd);
1046 1.6.2.2 nathanw DELAY(2);
1047 1.6.2.2 nathanw }
1048 1.6.2.2 nathanw if (len && (state->flags & DMA_IN_PROGRESS)) {
1049 1.6.2.2 nathanw /* save number of bytes still to be sent or received */
1050 1.6.2.2 nathanw state->dmaresid = len;
1051 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1052 1.6.2.2 nathanw ASC_TC_PUT(regs, 0, asc->is24bit);
1053 1.6.2.2 nathanw #ifdef DEBUG
1054 1.6.2.2 nathanw if (asc_logp == asc_log)
1055 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1056 1.6.2.2 nathanw else
1057 1.6.2.2 nathanw asc_logp[-1].resid = len;
1058 1.6.2.2 nathanw #endif
1059 1.6.2.2 nathanw /* setup state to resume to */
1060 1.6.2.2 nathanw if (state->flags & DMA_IN) {
1061 1.6.2.2 nathanw /*
1062 1.6.2.2 nathanw * Since the ASC_CNFG3_SRB bit of the
1063 1.6.2.2 nathanw * cnfg3 register bit is not set,
1064 1.6.2.2 nathanw * we just transferred an extra byte.
1065 1.6.2.2 nathanw * Since we can't resume on an odd byte
1066 1.6.2.2 nathanw * boundary, we copy the valid data out
1067 1.6.2.2 nathanw * and resume DMA at the start address.
1068 1.6.2.2 nathanw */
1069 1.6.2.2 nathanw if (len & 1) {
1070 1.6.2.2 nathanw printf("asc_intr: msg in len %d (fifo %d)\n",
1071 1.6.2.2 nathanw len, fifo); /* XXX */
1072 1.6.2.2 nathanw len = state->dmalen - len;
1073 1.6.2.2 nathanw goto do_in;
1074 1.6.2.2 nathanw }
1075 1.6.2.2 nathanw state->script =
1076 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_DMA_IN];
1077 1.6.2.2 nathanw } else if (state->flags & DMA_OUT)
1078 1.6.2.2 nathanw state->script =
1079 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_DMA_OUT];
1080 1.6.2.2 nathanw else
1081 1.6.2.2 nathanw state->script = asc->script;
1082 1.6.2.2 nathanw } else if (state->flags & DMA_IN) {
1083 1.6.2.2 nathanw if (len) {
1084 1.6.2.2 nathanw #ifdef DEBUG
1085 1.6.2.2 nathanw printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
1086 1.6.2.2 nathanw asc_debug_bn, len, fifo); /* XXX */
1087 1.6.2.2 nathanw #endif
1088 1.6.2.2 nathanw goto abort;
1089 1.6.2.2 nathanw }
1090 1.6.2.2 nathanw /* setup state to resume to */
1091 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1092 1.6.2.2 nathanw len = state->dmalen;
1093 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1094 1.6.2.2 nathanw do_in:
1095 1.6.2.2 nathanw DMA_END(asc->dma);
1096 1.6.2.2 nathanw state->buf += len;
1097 1.6.2.2 nathanw state->buflen -= len;
1098 1.6.2.2 nathanw }
1099 1.6.2.2 nathanw if (state->buflen)
1100 1.6.2.2 nathanw state->script =
1101 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_IN];
1102 1.6.2.2 nathanw else
1103 1.6.2.2 nathanw state->script =
1104 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_NO_DATA];
1105 1.6.2.2 nathanw } else if (state->flags & DMA_OUT) {
1106 1.6.2.2 nathanw if (len) {
1107 1.6.2.2 nathanw printf("asc_intr: 2: len %d (fifo %d)\n", len,
1108 1.6.2.2 nathanw fifo); /* XXX */
1109 1.6.2.2 nathanw /* XXX THEO */
1110 1.6.2.2 nathanw #if 1
1111 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1112 1.6.2.2 nathanw readback(regs->asc_cmd);
1113 1.6.2.2 nathanw DELAY(2);
1114 1.6.2.2 nathanw len = 0;
1115 1.6.2.2 nathanw #else
1116 1.6.2.2 nathanw goto abort;
1117 1.6.2.2 nathanw #endif
1118 1.6.2.2 nathanw }
1119 1.6.2.2 nathanw /*
1120 1.6.2.2 nathanw * If this is the last chunk, the next expected
1121 1.6.2.2 nathanw * state is to get status.
1122 1.6.2.2 nathanw */
1123 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1124 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1125 1.6.2.2 nathanw DMA_END(asc->dma);
1126 1.6.2.2 nathanw len = state->dmalen;
1127 1.6.2.2 nathanw state->buf += len;
1128 1.6.2.2 nathanw state->buflen -= len;
1129 1.6.2.2 nathanw }
1130 1.6.2.2 nathanw if (state->buflen)
1131 1.6.2.2 nathanw state->script =
1132 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_OUT];
1133 1.6.2.2 nathanw else
1134 1.6.2.2 nathanw state->script =
1135 1.6.2.2 nathanw &asc_scripts[SCRIPT_RESUME_NO_DATA];
1136 1.6.2.2 nathanw } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
1137 1.6.2.2 nathanw state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];
1138 1.6.2.2 nathanw else
1139 1.6.2.2 nathanw state->script = asc->script;
1140 1.6.2.2 nathanw
1141 1.6.2.2 nathanw /* setup to receive a message */
1142 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_MSG_IN];
1143 1.6.2.2 nathanw state->msglen = 0;
1144 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1145 1.6.2.2 nathanw readback(regs->asc_cmd);
1146 1.6.2.2 nathanw goto done;
1147 1.6.2.2 nathanw }
1148 1.6.2.2 nathanw
1149 1.6.2.2 nathanw /* check for SCSI bus reset */
1150 1.6.2.2 nathanw if (ir & ASC_INT_RESET) {
1151 1.6.2.2 nathanw register int i;
1152 1.6.2.2 nathanw
1153 1.6.2.2 nathanw printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname);
1154 1.6.2.2 nathanw /* need to flush any pending commands */
1155 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1156 1.6.2.2 nathanw if (!asc->cmd[i])
1157 1.6.2.2 nathanw continue;
1158 1.6.2.2 nathanw asc->cmd[i]->error = XS_DRIVER_STUFFUP;
1159 1.6.2.2 nathanw asc_end(asc, 0, 0, 0);
1160 1.6.2.2 nathanw }
1161 1.6.2.2 nathanw /* rearbitrate synchronous offset */
1162 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1163 1.6.2.2 nathanw asc->st[i].sync_offset = 0;
1164 1.6.2.2 nathanw asc->st[i].flags = 0;
1165 1.6.2.2 nathanw }
1166 1.6.2.2 nathanw asc->target = -1;
1167 1.6.2.2 nathanw return(1);
1168 1.6.2.2 nathanw }
1169 1.6.2.2 nathanw
1170 1.6.2.2 nathanw /* check for command errors */
1171 1.6.2.2 nathanw if (ir & ASC_INT_ILL)
1172 1.6.2.2 nathanw goto abort;
1173 1.6.2.2 nathanw
1174 1.6.2.2 nathanw /* check for disconnect */
1175 1.6.2.2 nathanw if (ir & ASC_INT_DISC) {
1176 1.6.2.2 nathanw state = &asc->st[asc->target];
1177 1.6.2.2 nathanw switch (asc->script - asc_scripts) {
1178 1.6.2.2 nathanw case SCRIPT_DONE:
1179 1.6.2.2 nathanw case SCRIPT_DISCONNECT:
1180 1.6.2.2 nathanw /*
1181 1.6.2.2 nathanw * Disconnects can happen normally when the
1182 1.6.2.2 nathanw * command is complete with the phase being
1183 1.6.2.2 nathanw * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN.
1184 1.6.2.2 nathanw * The SCRIPT_MATCH() only checks for one phase
1185 1.6.2.2 nathanw * so we can wind up here.
1186 1.6.2.2 nathanw * Perform the appropriate operation, then proceed.
1187 1.6.2.2 nathanw */
1188 1.6.2.2 nathanw if ((*scpt->action)(asc, status, ss, ir)) {
1189 1.6.2.2 nathanw regs->asc_cmd = scpt->command;
1190 1.6.2.2 nathanw readback(regs->asc_cmd);
1191 1.6.2.2 nathanw asc->script = scpt->next;
1192 1.6.2.2 nathanw }
1193 1.6.2.2 nathanw goto done;
1194 1.6.2.2 nathanw
1195 1.6.2.2 nathanw case SCRIPT_TRY_SYNC:
1196 1.6.2.2 nathanw case SCRIPT_SIMPLE:
1197 1.6.2.2 nathanw case SCRIPT_DATA_IN:
1198 1.6.2.2 nathanw case SCRIPT_DATA_OUT: /* one of the starting scripts */
1199 1.6.2.2 nathanw if (ASC_SS(ss) == 0) {
1200 1.6.2.2 nathanw /* device did not respond */
1201 1.6.2.2 nathanw if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {
1202 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1203 1.6.2.2 nathanw readback(regs->asc_cmd);
1204 1.6.2.2 nathanw }
1205 1.6.2.2 nathanw asc->cmd[asc->target]->error = XS_SELTIMEOUT;
1206 1.6.2.2 nathanw asc_end(asc, status, ss, ir);
1207 1.6.2.2 nathanw return(1);
1208 1.6.2.2 nathanw }
1209 1.6.2.2 nathanw /* FALLTHROUGH */
1210 1.6.2.2 nathanw
1211 1.6.2.2 nathanw default:
1212 1.6.2.2 nathanw printf("%s: SCSI device %d: unexpected disconnect\n",
1213 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target);
1214 1.6.2.2 nathanw #ifdef DEBUG
1215 1.6.2.2 nathanw asc_DumpLog("asc_disc");
1216 1.6.2.2 nathanw #endif
1217 1.6.2.2 nathanw /*
1218 1.6.2.2 nathanw * On rare occasions my RZ24 does a disconnect during
1219 1.6.2.2 nathanw * data in phase and the following seems to keep it
1220 1.6.2.2 nathanw * happy.
1221 1.6.2.2 nathanw * XXX Should a scsi disk ever do this??
1222 1.6.2.2 nathanw */
1223 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_RESEL];
1224 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
1225 1.6.2.2 nathanw state->flags |= DISCONN;
1226 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1227 1.6.2.2 nathanw readback(regs->asc_cmd);
1228 1.6.2.2 nathanw return(1);
1229 1.6.2.2 nathanw }
1230 1.6.2.2 nathanw }
1231 1.6.2.2 nathanw
1232 1.6.2.2 nathanw /* check for reselect */
1233 1.6.2.2 nathanw if (ir & ASC_INT_RESEL) {
1234 1.6.2.2 nathanw unsigned fifo, id, msg;
1235 1.6.2.2 nathanw
1236 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1237 1.6.2.2 nathanw if (fifo < 2)
1238 1.6.2.2 nathanw goto abort;
1239 1.6.2.2 nathanw /* read unencoded SCSI ID and convert to binary */
1240 1.6.2.2 nathanw msg = regs->asc_fifo & asc->myidmask;
1241 1.6.2.2 nathanw for (id = 0; (msg & 1) == 0; id++)
1242 1.6.2.2 nathanw msg >>= 1;
1243 1.6.2.2 nathanw /* read identify message */
1244 1.6.2.2 nathanw msg = regs->asc_fifo;
1245 1.6.2.2 nathanw #ifdef DEBUG
1246 1.6.2.2 nathanw if (asc_logp == asc_log)
1247 1.6.2.2 nathanw asc_log[NLOG - 1].msg = msg;
1248 1.6.2.2 nathanw else
1249 1.6.2.2 nathanw asc_logp[-1].msg = msg;
1250 1.6.2.2 nathanw #endif
1251 1.6.2.2 nathanw asc->state = ASC_STATE_BUSY;
1252 1.6.2.2 nathanw asc->target = id;
1253 1.6.2.2 nathanw state = &asc->st[id];
1254 1.6.2.2 nathanw asc->script = state->script;
1255 1.6.2.2 nathanw state->script = (script_t *)0;
1256 1.6.2.2 nathanw if (!(state->flags & DISCONN))
1257 1.6.2.2 nathanw goto abort;
1258 1.6.2.2 nathanw state->flags &= ~DISCONN;
1259 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1260 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1261 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1262 1.6.2.2 nathanw readback(regs->asc_cmd);
1263 1.6.2.2 nathanw goto done;
1264 1.6.2.2 nathanw }
1265 1.6.2.2 nathanw
1266 1.6.2.2 nathanw /* check if we are being selected as a target */
1267 1.6.2.2 nathanw if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
1268 1.6.2.2 nathanw goto abort;
1269 1.6.2.2 nathanw
1270 1.6.2.2 nathanw /*
1271 1.6.2.2 nathanw * 'ir' must be just ASC_INT_FC.
1272 1.6.2.2 nathanw * This is normal if canceling an ASC_ENABLE_SEL.
1273 1.6.2.2 nathanw */
1274 1.6.2.2 nathanw
1275 1.6.2.2 nathanw done:
1276 1.6.2.2 nathanw wbflush();
1277 1.6.2.2 nathanw /*
1278 1.6.2.2 nathanw * If the next interrupt comes in immediatly the interrupt
1279 1.6.2.2 nathanw * dispatcher (which we are returning to) will catch it
1280 1.6.2.2 nathanw * before returning to the interrupted code.
1281 1.6.2.2 nathanw */
1282 1.6.2.2 nathanw return(1);
1283 1.6.2.2 nathanw
1284 1.6.2.2 nathanw abort:
1285 1.6.2.2 nathanw #ifdef DEBUG
1286 1.6.2.2 nathanw asc_DumpLog("asc_intr");
1287 1.6.2.2 nathanw #endif
1288 1.6.2.2 nathanw panic("asc_intr");
1289 1.6.2.2 nathanw return(1);
1290 1.6.2.2 nathanw }
1291 1.6.2.2 nathanw
1292 1.6.2.2 nathanw /*
1293 1.6.2.2 nathanw * All the many little things that the interrupt
1294 1.6.2.2 nathanw * routine might switch to.
1295 1.6.2.2 nathanw */
1296 1.6.2.2 nathanw
1297 1.6.2.2 nathanw /* ARGSUSED */
1298 1.6.2.2 nathanw static int
1299 1.6.2.2 nathanw script_nop(asc, status, ss, ir)
1300 1.6.2.2 nathanw asc_softc_t asc;
1301 1.6.2.2 nathanw int status, ss, ir;
1302 1.6.2.2 nathanw {
1303 1.6.2.2 nathanw return (1);
1304 1.6.2.2 nathanw }
1305 1.6.2.2 nathanw
1306 1.6.2.2 nathanw /* ARGSUSED */
1307 1.6.2.2 nathanw static int
1308 1.6.2.2 nathanw asc_get_status(asc, status, ss, ir)
1309 1.6.2.2 nathanw register asc_softc_t asc;
1310 1.6.2.2 nathanw register int status, ss, ir;
1311 1.6.2.2 nathanw {
1312 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1313 1.6.2.2 nathanw register int data;
1314 1.6.2.2 nathanw
1315 1.6.2.2 nathanw /*
1316 1.6.2.2 nathanw * Get the last two bytes in the FIFO.
1317 1.6.2.2 nathanw */
1318 1.6.2.2 nathanw if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
1319 1.6.2.2 nathanw printf("asc_get_status: cmdreg %x, fifo cnt %d\n",
1320 1.6.2.2 nathanw regs->asc_cmd, data); /* XXX */
1321 1.6.2.2 nathanw #ifdef DEBUG
1322 1.6.2.2 nathanw asc_DumpLog("get_status"); /* XXX */
1323 1.6.2.2 nathanw #endif
1324 1.6.2.2 nathanw if (data < 2) {
1325 1.6.2.2 nathanw asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
1326 1.6.2.2 nathanw readback(asc->regs->asc_cmd);
1327 1.6.2.2 nathanw return (0);
1328 1.6.2.2 nathanw }
1329 1.6.2.2 nathanw do {
1330 1.6.2.2 nathanw data = regs->asc_fifo;
1331 1.6.2.2 nathanw } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
1332 1.6.2.2 nathanw }
1333 1.6.2.2 nathanw
1334 1.6.2.2 nathanw /* save the status byte */
1335 1.6.2.2 nathanw asc->st[asc->target].statusByte = data = regs->asc_fifo;
1336 1.6.2.2 nathanw #ifdef DEBUG
1337 1.6.2.2 nathanw if (asc_logp == asc_log)
1338 1.6.2.2 nathanw asc_log[NLOG - 1].msg = data;
1339 1.6.2.2 nathanw else
1340 1.6.2.2 nathanw asc_logp[-1].msg = data;
1341 1.6.2.2 nathanw #endif
1342 1.6.2.2 nathanw
1343 1.6.2.2 nathanw /* get the (presumed) command_complete message */
1344 1.6.2.2 nathanw if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
1345 1.6.2.2 nathanw return (1);
1346 1.6.2.2 nathanw
1347 1.6.2.2 nathanw #ifdef DEBUG
1348 1.6.2.2 nathanw printf("asc_get_status: status %x cmd %x\n",
1349 1.6.2.2 nathanw asc->st[asc->target].statusByte, data);
1350 1.6.2.2 nathanw asc_DumpLog("asc_get_status");
1351 1.6.2.2 nathanw #endif
1352 1.6.2.2 nathanw return (0);
1353 1.6.2.2 nathanw }
1354 1.6.2.2 nathanw
1355 1.6.2.2 nathanw /* ARGSUSED */
1356 1.6.2.2 nathanw static int
1357 1.6.2.2 nathanw asc_end(asc, status, ss, ir)
1358 1.6.2.2 nathanw asc_softc_t asc;
1359 1.6.2.2 nathanw int status, ss, ir;
1360 1.6.2.2 nathanw {
1361 1.6.2.2 nathanw struct scsipi_xfer *scsicmd;
1362 1.6.2.2 nathanw struct scsipi_periph *periph;
1363 1.6.2.2 nathanw State *state;
1364 1.6.2.2 nathanw int i, target;
1365 1.6.2.2 nathanw
1366 1.6.2.2 nathanw asc->state = ASC_STATE_IDLE;
1367 1.6.2.2 nathanw target = asc->target;
1368 1.6.2.2 nathanw asc->target = -1;
1369 1.6.2.2 nathanw scsicmd = asc->cmd[target];
1370 1.6.2.2 nathanw periph = scsicmd->xs_periph;
1371 1.6.2.2 nathanw asc->cmd[target] = (struct scsipi_xfer *)0;
1372 1.6.2.2 nathanw state = &asc->st[target];
1373 1.6.2.2 nathanw
1374 1.6.2.2 nathanw #ifdef DEBUG
1375 1.6.2.2 nathanw if (asc_debug > 1) {
1376 1.6.2.2 nathanw printf("asc_end: %s target %d cmd %x err %d resid %d\n",
1377 1.6.2.2 nathanw asc->sc_dev.dv_xname, target,
1378 1.6.2.2 nathanw state->cmd.opcode, scsicmd->error, state->buflen);
1379 1.6.2.2 nathanw }
1380 1.6.2.2 nathanw #endif
1381 1.6.2.2 nathanw #ifdef DIAGNOSTIC
1382 1.6.2.2 nathanw if (target < 0 || !scsicmd)
1383 1.6.2.2 nathanw panic("asc_end");
1384 1.6.2.2 nathanw #endif
1385 1.6.2.2 nathanw
1386 1.6.2.2 nathanw /* look for disconnected devices */
1387 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1388 1.6.2.2 nathanw if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
1389 1.6.2.2 nathanw continue;
1390 1.6.2.2 nathanw asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
1391 1.6.2.2 nathanw readback(asc->regs->asc_cmd);
1392 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
1393 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_RESEL];
1394 1.6.2.2 nathanw break;
1395 1.6.2.2 nathanw }
1396 1.6.2.2 nathanw
1397 1.6.2.2 nathanw if(scsicmd->error == XS_NOERROR) {
1398 1.6.2.2 nathanw if((state->statusByte & ST_MASK) == SCSI_CHECK) {
1399 1.6.2.2 nathanw scsicmd->status = state->statusByte;
1400 1.6.2.2 nathanw scsicmd->error = XS_BUSY;
1401 1.6.2.2 nathanw }
1402 1.6.2.2 nathanw }
1403 1.6.2.2 nathanw
1404 1.6.2.2 nathanw scsicmd->resid = state->buflen;
1405 1.6.2.2 nathanw
1406 1.6.2.2 nathanw /*
1407 1.6.2.2 nathanw * Look for another device that is ready.
1408 1.6.2.2 nathanw * May want to keep last one started and increment for fairness
1409 1.6.2.2 nathanw * rather than always starting at zero.
1410 1.6.2.2 nathanw */
1411 1.6.2.2 nathanw for (i = 0; i < ASC_NCMD; i++) {
1412 1.6.2.2 nathanw /* don't restart a disconnected command */
1413 1.6.2.2 nathanw if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
1414 1.6.2.2 nathanw continue;
1415 1.6.2.2 nathanw asc_startcmd(asc, i);
1416 1.6.2.2 nathanw break;
1417 1.6.2.2 nathanw }
1418 1.6.2.2 nathanw
1419 1.6.2.2 nathanw /* signal device driver that the command is done */
1420 1.6.2.2 nathanw scsipi_done(scsicmd);
1421 1.6.2.2 nathanw
1422 1.6.2.2 nathanw return (0);
1423 1.6.2.2 nathanw }
1424 1.6.2.2 nathanw
1425 1.6.2.2 nathanw /* ARGSUSED */
1426 1.6.2.2 nathanw static int
1427 1.6.2.2 nathanw asc_dma_in(asc, status, ss, ir)
1428 1.6.2.2 nathanw register asc_softc_t asc;
1429 1.6.2.2 nathanw register int status, ss, ir;
1430 1.6.2.2 nathanw {
1431 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1432 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1433 1.6.2.2 nathanw register int len;
1434 1.6.2.2 nathanw
1435 1.6.2.2 nathanw /* check for previous chunk in buffer */
1436 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1437 1.6.2.2 nathanw /*
1438 1.6.2.2 nathanw * Only count bytes that have been copied to memory.
1439 1.6.2.2 nathanw * There may be some bytes in the FIFO if synchonous transfers
1440 1.6.2.2 nathanw * are in progress.
1441 1.6.2.2 nathanw */
1442 1.6.2.2 nathanw DMA_END(asc->dma);
1443 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1444 1.6.2.2 nathanw len = state->dmalen - len;
1445 1.6.2.2 nathanw state->buf += len;
1446 1.6.2.2 nathanw state->buflen -= len;
1447 1.6.2.2 nathanw }
1448 1.6.2.2 nathanw
1449 1.6.2.2 nathanw /* setup to start reading the next chunk */
1450 1.6.2.2 nathanw len = state->buflen;
1451 1.6.2.2 nathanw #ifdef DEBUG
1452 1.6.2.2 nathanw if (asc_logp == asc_log)
1453 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1454 1.6.2.2 nathanw else
1455 1.6.2.2 nathanw asc_logp[-1].resid = len;
1456 1.6.2.2 nathanw #endif
1457 1.6.2.2 nathanw if (len > state->dmaBufSize)
1458 1.6.2.2 nathanw len = state->dmaBufSize;
1459 1.6.2.2 nathanw state->dmalen = len;
1460 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
1461 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1462 1.6.2.2 nathanw #ifdef DEBUG
1463 1.6.2.2 nathanw if (asc_debug > 2)
1464 1.6.2.2 nathanw printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
1465 1.6.2.2 nathanw #endif
1466 1.6.2.2 nathanw
1467 1.6.2.2 nathanw /* check for next chunk */
1468 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1469 1.6.2.2 nathanw if (len != state->buflen) {
1470 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1471 1.6.2.2 nathanw readback(regs->asc_cmd);
1472 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1473 1.6.2.2 nathanw return (0);
1474 1.6.2.2 nathanw }
1475 1.6.2.2 nathanw return (1);
1476 1.6.2.2 nathanw }
1477 1.6.2.2 nathanw
1478 1.6.2.2 nathanw /* ARGSUSED */
1479 1.6.2.2 nathanw static int
1480 1.6.2.2 nathanw asc_last_dma_in(asc, status, ss, ir)
1481 1.6.2.2 nathanw register asc_softc_t asc;
1482 1.6.2.2 nathanw register int status, ss, ir;
1483 1.6.2.2 nathanw {
1484 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1485 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1486 1.6.2.2 nathanw register int len, fifo;
1487 1.6.2.2 nathanw
1488 1.6.2.2 nathanw DMA_END(asc->dma);
1489 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1490 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1491 1.6.2.2 nathanw #ifdef DEBUG
1492 1.6.2.2 nathanw if (asc_debug > 2)
1493 1.6.2.2 nathanw printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
1494 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
1495 1.6.2.2 nathanw #endif
1496 1.6.2.2 nathanw if (fifo) {
1497 1.6.2.2 nathanw /* device must be trying to send more than we expect */
1498 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1499 1.6.2.2 nathanw readback(regs->asc_cmd);
1500 1.6.2.2 nathanw }
1501 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1502 1.6.2.2 nathanw len = state->dmalen - len;
1503 1.6.2.2 nathanw state->buflen -= len;
1504 1.6.2.2 nathanw
1505 1.6.2.2 nathanw return (1);
1506 1.6.2.2 nathanw }
1507 1.6.2.2 nathanw
1508 1.6.2.2 nathanw /* ARGSUSED */
1509 1.6.2.2 nathanw static int
1510 1.6.2.2 nathanw asc_resume_in(asc, status, ss, ir)
1511 1.6.2.2 nathanw register asc_softc_t asc;
1512 1.6.2.2 nathanw register int status, ss, ir;
1513 1.6.2.2 nathanw {
1514 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1515 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1516 1.6.2.2 nathanw register int len;
1517 1.6.2.2 nathanw
1518 1.6.2.2 nathanw /* setup to start reading the next chunk */
1519 1.6.2.2 nathanw len = state->buflen;
1520 1.6.2.2 nathanw #ifdef DEBUG
1521 1.6.2.2 nathanw if (asc_logp == asc_log)
1522 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1523 1.6.2.2 nathanw else
1524 1.6.2.2 nathanw asc_logp[-1].resid = len;
1525 1.6.2.2 nathanw #endif
1526 1.6.2.2 nathanw if (len > state->dmaBufSize)
1527 1.6.2.2 nathanw len = state->dmaBufSize;
1528 1.6.2.2 nathanw state->dmalen = len;
1529 1.6.2.2 nathanw #ifdef DEBUG
1530 1.6.2.2 nathanw if (asc_logp == asc_log)
1531 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1532 1.6.2.2 nathanw else
1533 1.6.2.2 nathanw asc_logp[-1].resid = len;
1534 1.6.2.2 nathanw #endif
1535 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
1536 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1537 1.6.2.2 nathanw #ifdef DEBUG
1538 1.6.2.2 nathanw if (asc_debug > 2)
1539 1.6.2.2 nathanw printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
1540 1.6.2.2 nathanw len);
1541 1.6.2.2 nathanw #endif
1542 1.6.2.2 nathanw
1543 1.6.2.2 nathanw /* check for next chunk */
1544 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1545 1.6.2.2 nathanw if (len != state->buflen) {
1546 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1547 1.6.2.2 nathanw readback(regs->asc_cmd);
1548 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1549 1.6.2.2 nathanw return (0);
1550 1.6.2.2 nathanw }
1551 1.6.2.2 nathanw return (1);
1552 1.6.2.2 nathanw }
1553 1.6.2.2 nathanw
1554 1.6.2.2 nathanw /* ARGSUSED */
1555 1.6.2.2 nathanw static int
1556 1.6.2.2 nathanw asc_resume_dma_in(asc, status, ss, ir)
1557 1.6.2.2 nathanw register asc_softc_t asc;
1558 1.6.2.2 nathanw register int status, ss, ir;
1559 1.6.2.2 nathanw {
1560 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1561 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1562 1.6.2.2 nathanw register int len, off;
1563 1.6.2.2 nathanw
1564 1.6.2.2 nathanw /* setup to finish reading the current chunk */
1565 1.6.2.2 nathanw len = state->dmaresid;
1566 1.6.2.2 nathanw off = state->dmalen - len;
1567 1.6.2.2 nathanw if ((off & 1) && state->sync_offset) {
1568 1.6.2.2 nathanw printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
1569 1.6.2.2 nathanw state->dmalen, len, off); /* XXX */
1570 1.6.2.2 nathanw regs->asc_res_fifo = ((u_char *)state->buf)[off];
1571 1.6.2.2 nathanw /*XXX Need to flush cache ? */
1572 1.6.2.2 nathanw }
1573 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV);
1574 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1575 1.6.2.2 nathanw #ifdef DEBUG
1576 1.6.2.2 nathanw if (asc_debug > 2)
1577 1.6.2.2 nathanw printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
1578 1.6.2.2 nathanw state->dmalen, state->buflen, len, off);
1579 1.6.2.2 nathanw #endif
1580 1.6.2.2 nathanw
1581 1.6.2.2 nathanw /* check for next chunk */
1582 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1583 1.6.2.2 nathanw if (state->dmalen != state->buflen) {
1584 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1585 1.6.2.2 nathanw readback(regs->asc_cmd);
1586 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
1587 1.6.2.2 nathanw return (0);
1588 1.6.2.2 nathanw }
1589 1.6.2.2 nathanw return (1);
1590 1.6.2.2 nathanw }
1591 1.6.2.2 nathanw
1592 1.6.2.2 nathanw /* ARGSUSED */
1593 1.6.2.2 nathanw static int
1594 1.6.2.2 nathanw asc_dma_out(asc, status, ss, ir)
1595 1.6.2.2 nathanw register asc_softc_t asc;
1596 1.6.2.2 nathanw register int status, ss, ir;
1597 1.6.2.2 nathanw {
1598 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1599 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1600 1.6.2.2 nathanw register int len, fifo;
1601 1.6.2.2 nathanw
1602 1.6.2.2 nathanw if (state->flags & DMA_IN_PROGRESS) {
1603 1.6.2.2 nathanw /* check to be sure previous chunk was finished */
1604 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1605 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1606 1.6.2.2 nathanw if (len || fifo)
1607 1.6.2.2 nathanw printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1608 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo); /* XXX */
1609 1.6.2.2 nathanw len += fifo;
1610 1.6.2.2 nathanw len = state->dmalen - len;
1611 1.6.2.2 nathanw state->buf += len;
1612 1.6.2.2 nathanw state->buflen -= len;
1613 1.6.2.2 nathanw }
1614 1.6.2.2 nathanw
1615 1.6.2.2 nathanw /* setup for this chunk */
1616 1.6.2.2 nathanw len = state->buflen;
1617 1.6.2.2 nathanw #ifdef DEBUG
1618 1.6.2.2 nathanw if (asc_logp == asc_log)
1619 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1620 1.6.2.2 nathanw else
1621 1.6.2.2 nathanw asc_logp[-1].resid = len;
1622 1.6.2.2 nathanw #endif
1623 1.6.2.2 nathanw if (len > state->dmaBufSize)
1624 1.6.2.2 nathanw len = state->dmaBufSize;
1625 1.6.2.2 nathanw state->dmalen = len;
1626 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
1627 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1628 1.6.2.2 nathanw #ifdef DEBUG
1629 1.6.2.2 nathanw if (asc_debug > 2)
1630 1.6.2.2 nathanw printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
1631 1.6.2.2 nathanw #endif
1632 1.6.2.2 nathanw
1633 1.6.2.2 nathanw /* check for next chunk */
1634 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1635 1.6.2.2 nathanw if (len != state->buflen) {
1636 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1637 1.6.2.2 nathanw readback(regs->asc_cmd);
1638 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1639 1.6.2.2 nathanw return (0);
1640 1.6.2.2 nathanw }
1641 1.6.2.2 nathanw return (1);
1642 1.6.2.2 nathanw }
1643 1.6.2.2 nathanw
1644 1.6.2.2 nathanw /* ARGSUSED */
1645 1.6.2.2 nathanw static int
1646 1.6.2.2 nathanw asc_last_dma_out(asc, status, ss, ir)
1647 1.6.2.2 nathanw register asc_softc_t asc;
1648 1.6.2.2 nathanw register int status, ss, ir;
1649 1.6.2.2 nathanw {
1650 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1651 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1652 1.6.2.2 nathanw register int len, fifo;
1653 1.6.2.2 nathanw
1654 1.6.2.2 nathanw ASC_TC_GET(regs, len);
1655 1.6.2.2 nathanw fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
1656 1.6.2.2 nathanw #ifdef DEBUG
1657 1.6.2.2 nathanw if (asc_debug > 2)
1658 1.6.2.2 nathanw printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
1659 1.6.2.2 nathanw state->buflen, state->dmalen, len, fifo);
1660 1.6.2.2 nathanw #endif
1661 1.6.2.2 nathanw if (fifo) {
1662 1.6.2.2 nathanw len += fifo;
1663 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_FLUSH;
1664 1.6.2.2 nathanw readback(regs->asc_cmd);
1665 1.6.2.2 nathanw }
1666 1.6.2.2 nathanw state->flags &= ~DMA_IN_PROGRESS;
1667 1.6.2.2 nathanw len = state->dmalen - len;
1668 1.6.2.2 nathanw state->buflen -= len;
1669 1.6.2.2 nathanw return (1);
1670 1.6.2.2 nathanw }
1671 1.6.2.2 nathanw
1672 1.6.2.2 nathanw /* ARGSUSED */
1673 1.6.2.2 nathanw static int
1674 1.6.2.2 nathanw asc_resume_out(asc, status, ss, ir)
1675 1.6.2.2 nathanw register asc_softc_t asc;
1676 1.6.2.2 nathanw register int status, ss, ir;
1677 1.6.2.2 nathanw {
1678 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1679 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1680 1.6.2.2 nathanw register int len;
1681 1.6.2.2 nathanw
1682 1.6.2.2 nathanw /* setup for this chunk */
1683 1.6.2.2 nathanw len = state->buflen;
1684 1.6.2.2 nathanw #ifdef DEBUG
1685 1.6.2.2 nathanw if (asc_logp == asc_log)
1686 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1687 1.6.2.2 nathanw else
1688 1.6.2.2 nathanw asc_logp[-1].resid = len;
1689 1.6.2.2 nathanw #endif
1690 1.6.2.2 nathanw if (len > state->dmaBufSize)
1691 1.6.2.2 nathanw len = state->dmaBufSize;
1692 1.6.2.2 nathanw state->dmalen = len;
1693 1.6.2.2 nathanw #ifdef DEBUG
1694 1.6.2.2 nathanw if (asc_logp == asc_log)
1695 1.6.2.2 nathanw asc_log[NLOG - 1].resid = len;
1696 1.6.2.2 nathanw else
1697 1.6.2.2 nathanw asc_logp[-1].resid = len;
1698 1.6.2.2 nathanw #endif
1699 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
1700 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1701 1.6.2.2 nathanw #ifdef DEBUG
1702 1.6.2.2 nathanw if (asc_debug > 2)
1703 1.6.2.2 nathanw printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
1704 1.6.2.2 nathanw len);
1705 1.6.2.2 nathanw #endif
1706 1.6.2.2 nathanw
1707 1.6.2.2 nathanw /* check for next chunk */
1708 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1709 1.6.2.2 nathanw if (len != state->buflen) {
1710 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1711 1.6.2.2 nathanw readback(regs->asc_cmd);
1712 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1713 1.6.2.2 nathanw return (0);
1714 1.6.2.2 nathanw }
1715 1.6.2.2 nathanw return (1);
1716 1.6.2.2 nathanw }
1717 1.6.2.2 nathanw
1718 1.6.2.2 nathanw /* ARGSUSED */
1719 1.6.2.2 nathanw static int
1720 1.6.2.2 nathanw asc_resume_dma_out(asc, status, ss, ir)
1721 1.6.2.2 nathanw register asc_softc_t asc;
1722 1.6.2.2 nathanw register int status, ss, ir;
1723 1.6.2.2 nathanw {
1724 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1725 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1726 1.6.2.2 nathanw register int len, off;
1727 1.6.2.2 nathanw
1728 1.6.2.2 nathanw /* setup to finish writing this chunk */
1729 1.6.2.2 nathanw len = state->dmaresid;
1730 1.6.2.2 nathanw off = state->dmalen - len;
1731 1.6.2.2 nathanw if (off & 1) {
1732 1.6.2.2 nathanw printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
1733 1.6.2.2 nathanw state->dmalen, len, off); /* XXX */
1734 1.6.2.2 nathanw regs->asc_fifo = ((u_char *)state->buf)[off];
1735 1.6.2.2 nathanw /*XXX Need to flush Cache ? */
1736 1.6.2.2 nathanw off++;
1737 1.6.2.2 nathanw len--;
1738 1.6.2.2 nathanw }
1739 1.6.2.2 nathanw DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV);
1740 1.6.2.2 nathanw ASC_TC_PUT(regs, len, asc->is24bit);
1741 1.6.2.2 nathanw #ifdef DEBUG
1742 1.6.2.2 nathanw if (asc_debug > 2)
1743 1.6.2.2 nathanw printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
1744 1.6.2.2 nathanw state->dmalen, state->buflen, len, off);
1745 1.6.2.2 nathanw #endif
1746 1.6.2.2 nathanw
1747 1.6.2.2 nathanw /* check for next chunk */
1748 1.6.2.2 nathanw state->flags |= DMA_IN_PROGRESS;
1749 1.6.2.2 nathanw if (state->dmalen != state->buflen) {
1750 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
1751 1.6.2.2 nathanw readback(regs->asc_cmd);
1752 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
1753 1.6.2.2 nathanw return (0);
1754 1.6.2.2 nathanw }
1755 1.6.2.2 nathanw return (1);
1756 1.6.2.2 nathanw }
1757 1.6.2.2 nathanw
1758 1.6.2.2 nathanw /* ARGSUSED */
1759 1.6.2.2 nathanw static int
1760 1.6.2.2 nathanw asc_sendsync(asc, status, ss, ir)
1761 1.6.2.2 nathanw register asc_softc_t asc;
1762 1.6.2.2 nathanw register int status, ss, ir;
1763 1.6.2.2 nathanw {
1764 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1765 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1766 1.6.2.2 nathanw
1767 1.6.2.2 nathanw /* send the extended synchronous negotiation message */
1768 1.6.2.2 nathanw regs->asc_fifo = SCSI_EXTENDED_MSG;
1769 1.6.2.2 nathanw wbflush();
1770 1.6.2.2 nathanw regs->asc_fifo = 3;
1771 1.6.2.2 nathanw wbflush();
1772 1.6.2.2 nathanw regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1773 1.6.2.2 nathanw wbflush();
1774 1.6.2.2 nathanw regs->asc_fifo = SCSI_MIN_PERIOD;
1775 1.6.2.2 nathanw wbflush();
1776 1.6.2.2 nathanw regs->asc_fifo = ASC_MAX_OFFSET;
1777 1.6.2.2 nathanw /* state to resume after we see the sync reply message */
1778 1.6.2.2 nathanw state->script = asc->script + 2;
1779 1.6.2.2 nathanw state->msglen = 0;
1780 1.6.2.2 nathanw return (1);
1781 1.6.2.2 nathanw }
1782 1.6.2.2 nathanw
1783 1.6.2.2 nathanw /* ARGSUSED */
1784 1.6.2.2 nathanw static int
1785 1.6.2.2 nathanw asc_replysync(asc, status, ss, ir)
1786 1.6.2.2 nathanw register asc_softc_t asc;
1787 1.6.2.2 nathanw register int status, ss, ir;
1788 1.6.2.2 nathanw {
1789 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1790 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1791 1.6.2.2 nathanw
1792 1.6.2.2 nathanw #ifdef DEBUG
1793 1.6.2.2 nathanw if (asc_debug > 2)
1794 1.6.2.2 nathanw printf("asc_replysync: %x %x\n",
1795 1.6.2.2 nathanw asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
1796 1.6.2.2 nathanw state->sync_offset);
1797 1.6.2.2 nathanw #endif
1798 1.6.2.2 nathanw /* send synchronous transfer in response to a request */
1799 1.6.2.2 nathanw regs->asc_fifo = SCSI_EXTENDED_MSG;
1800 1.6.2.2 nathanw wbflush();
1801 1.6.2.2 nathanw regs->asc_fifo = 3;
1802 1.6.2.2 nathanw wbflush();
1803 1.6.2.2 nathanw regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
1804 1.6.2.2 nathanw wbflush();
1805 1.6.2.2 nathanw regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
1806 1.6.2.2 nathanw wbflush();
1807 1.6.2.2 nathanw regs->asc_fifo = state->sync_offset;
1808 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1809 1.6.2.2 nathanw readback(regs->asc_cmd);
1810 1.6.2.2 nathanw
1811 1.6.2.2 nathanw /* return to the appropriate script */
1812 1.6.2.2 nathanw if (!state->script) {
1813 1.6.2.2 nathanw #ifdef DEBUG
1814 1.6.2.2 nathanw asc_DumpLog("asc_replsync");
1815 1.6.2.2 nathanw #endif
1816 1.6.2.2 nathanw panic("asc_replysync");
1817 1.6.2.2 nathanw }
1818 1.6.2.2 nathanw asc->script = state->script;
1819 1.6.2.2 nathanw state->script = (script_t *)0;
1820 1.6.2.2 nathanw return (0);
1821 1.6.2.2 nathanw }
1822 1.6.2.2 nathanw
1823 1.6.2.2 nathanw /* ARGSUSED */
1824 1.6.2.2 nathanw static int
1825 1.6.2.2 nathanw asc_msg_in(asc, status, ss, ir)
1826 1.6.2.2 nathanw register asc_softc_t asc;
1827 1.6.2.2 nathanw register int status, ss, ir;
1828 1.6.2.2 nathanw {
1829 1.6.2.2 nathanw register asc_regmap_t *regs = asc->regs;
1830 1.6.2.2 nathanw register State *state = &asc->st[asc->target];
1831 1.6.2.2 nathanw register int msg;
1832 1.6.2.2 nathanw int i;
1833 1.6.2.2 nathanw
1834 1.6.2.2 nathanw /* read one message byte */
1835 1.6.2.2 nathanw msg = regs->asc_fifo;
1836 1.6.2.2 nathanw #ifdef DEBUG
1837 1.6.2.2 nathanw if (asc_logp == asc_log)
1838 1.6.2.2 nathanw asc_log[NLOG - 1].msg = msg;
1839 1.6.2.2 nathanw else
1840 1.6.2.2 nathanw asc_logp[-1].msg = msg;
1841 1.6.2.2 nathanw #endif
1842 1.6.2.2 nathanw
1843 1.6.2.2 nathanw /* check for multi-byte message */
1844 1.6.2.2 nathanw if (state->msglen != 0) {
1845 1.6.2.2 nathanw /* first byte is the message length */
1846 1.6.2.2 nathanw if (state->msglen < 0) {
1847 1.6.2.2 nathanw state->msglen = msg;
1848 1.6.2.2 nathanw return (1);
1849 1.6.2.2 nathanw }
1850 1.6.2.2 nathanw if (state->msgcnt >= state->msglen)
1851 1.6.2.2 nathanw goto abort;
1852 1.6.2.2 nathanw state->msg_in[state->msgcnt++] = msg;
1853 1.6.2.2 nathanw
1854 1.6.2.2 nathanw /* did we just read the last byte of the message? */
1855 1.6.2.2 nathanw if (state->msgcnt != state->msglen)
1856 1.6.2.2 nathanw return (1);
1857 1.6.2.2 nathanw
1858 1.6.2.2 nathanw /* process an extended message */
1859 1.6.2.2 nathanw #ifdef DEBUG
1860 1.6.2.2 nathanw if (asc_debug > 2)
1861 1.6.2.2 nathanw printf("asc_msg_in: msg %x %x %x\n",
1862 1.6.2.2 nathanw state->msg_in[0],
1863 1.6.2.2 nathanw state->msg_in[1],
1864 1.6.2.2 nathanw state->msg_in[2]);
1865 1.6.2.2 nathanw #endif
1866 1.6.2.2 nathanw switch (state->msg_in[0]) {
1867 1.6.2.2 nathanw case SCSI_SYNCHRONOUS_XFER:
1868 1.6.2.2 nathanw state->flags |= DID_SYNC;
1869 1.6.2.2 nathanw state->sync_offset = state->msg_in[2];
1870 1.6.2.2 nathanw
1871 1.6.2.2 nathanw /* convert SCSI period to ASC period */
1872 1.6.2.2 nathanw i = state->msg_in[1] / asc->tb_ticks;
1873 1.6.2.2 nathanw if (i < asc->min_period)
1874 1.6.2.2 nathanw i = asc->min_period;
1875 1.6.2.2 nathanw else if (i >= asc->max_period) {
1876 1.6.2.2 nathanw /* can't do sync transfer, period too long */
1877 1.6.2.2 nathanw printf("%s: SCSI device %d: sync xfer period too long (%d)\n",
1878 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target, i);
1879 1.6.2.2 nathanw i = asc->max_period;
1880 1.6.2.2 nathanw state->sync_offset = 0;
1881 1.6.2.2 nathanw }
1882 1.6.2.2 nathanw if ((i * asc->tb_ticks) != state->msg_in[1])
1883 1.6.2.2 nathanw i++;
1884 1.6.2.2 nathanw state->sync_period = i & 0x1F;
1885 1.6.2.2 nathanw
1886 1.6.2.2 nathanw /*
1887 1.6.2.2 nathanw * If this is a request, check minimums and
1888 1.6.2.2 nathanw * send back an acknowledge.
1889 1.6.2.2 nathanw */
1890 1.6.2.2 nathanw if (!(state->flags & TRY_SYNC)) {
1891 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SET_ATN;
1892 1.6.2.2 nathanw readback(regs->asc_cmd);
1893 1.6.2.2 nathanw
1894 1.6.2.2 nathanw if (state->sync_period < asc->min_period)
1895 1.6.2.2 nathanw state->sync_period =
1896 1.6.2.2 nathanw asc->min_period;
1897 1.6.2.2 nathanw if (state->sync_offset > ASC_MAX_OFFSET)
1898 1.6.2.2 nathanw state->sync_offset =
1899 1.6.2.2 nathanw ASC_MAX_OFFSET;
1900 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
1901 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1902 1.6.2.2 nathanw readback(regs->asc_syn_p);
1903 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1904 1.6.2.2 nathanw readback(regs->asc_syn_o);
1905 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1906 1.6.2.2 nathanw readback(regs->asc_cmd);
1907 1.6.2.2 nathanw return (0);
1908 1.6.2.2 nathanw }
1909 1.6.2.2 nathanw
1910 1.6.2.2 nathanw regs->asc_syn_p = state->sync_period;
1911 1.6.2.2 nathanw readback(regs->asc_syn_p);
1912 1.6.2.2 nathanw regs->asc_syn_o = state->sync_offset;
1913 1.6.2.2 nathanw readback(regs->asc_syn_o);
1914 1.6.2.2 nathanw goto done;
1915 1.6.2.2 nathanw
1916 1.6.2.2 nathanw default:
1917 1.6.2.2 nathanw printf("%s: SCSI device %d: rejecting extended message 0x%x\n",
1918 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target,
1919 1.6.2.2 nathanw state->msg_in[0]);
1920 1.6.2.2 nathanw goto reject;
1921 1.6.2.2 nathanw }
1922 1.6.2.2 nathanw }
1923 1.6.2.2 nathanw
1924 1.6.2.2 nathanw /* process first byte of a message */
1925 1.6.2.2 nathanw #ifdef DEBUG
1926 1.6.2.2 nathanw if (asc_debug > 2)
1927 1.6.2.2 nathanw printf("asc_msg_in: msg %x\n", msg);
1928 1.6.2.2 nathanw #endif
1929 1.6.2.2 nathanw switch (msg) {
1930 1.6.2.2 nathanw #if 0
1931 1.6.2.2 nathanw case SCSI_MESSAGE_REJECT:
1932 1.6.2.2 nathanw printf(" did not like SYNCH xfer "); /* XXX */
1933 1.6.2.2 nathanw state->flags |= DID_SYNC;
1934 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1935 1.6.2.2 nathanw readback(regs->asc_cmd);
1936 1.6.2.2 nathanw status = asc_wait(regs, ASC_CSR_INT);
1937 1.6.2.2 nathanw ir = regs->asc_intr;
1938 1.6.2.2 nathanw /* some just break out here, some dont */
1939 1.6.2.2 nathanw if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
1940 1.6.2.2 nathanw regs->asc_fifo = SCSI_ABORT;
1941 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_XFER_INFO;
1942 1.6.2.2 nathanw readback(regs->asc_cmd);
1943 1.6.2.2 nathanw status = asc_wait(regs, ASC_CSR_INT);
1944 1.6.2.2 nathanw ir = regs->asc_intr;
1945 1.6.2.2 nathanw }
1946 1.6.2.2 nathanw if (ir & ASC_INT_DISC) {
1947 1.6.2.2 nathanw asc_end(asc, status, 0, ir);
1948 1.6.2.2 nathanw return (0);
1949 1.6.2.2 nathanw }
1950 1.6.2.2 nathanw goto status;
1951 1.6.2.2 nathanw #endif /* 0 */
1952 1.6.2.2 nathanw
1953 1.6.2.2 nathanw case SCSI_EXTENDED_MSG: /* read an extended message */
1954 1.6.2.2 nathanw /* setup to read message length next */
1955 1.6.2.2 nathanw state->msglen = -1;
1956 1.6.2.2 nathanw state->msgcnt = 0;
1957 1.6.2.2 nathanw return (1);
1958 1.6.2.2 nathanw
1959 1.6.2.2 nathanw case SCSI_NO_OP:
1960 1.6.2.2 nathanw break;
1961 1.6.2.2 nathanw
1962 1.6.2.2 nathanw case SCSI_SAVE_DATA_POINTER:
1963 1.6.2.2 nathanw /* expect another message */
1964 1.6.2.2 nathanw return (1);
1965 1.6.2.2 nathanw
1966 1.6.2.2 nathanw case SCSI_RESTORE_POINTERS:
1967 1.6.2.2 nathanw /*
1968 1.6.2.2 nathanw * Need to do the following if resuming synchonous data in
1969 1.6.2.2 nathanw * on an odd byte boundary.
1970 1.6.2.2 nathanw regs->asc_cnfg2 |= ASC_CNFG2_RFB;
1971 1.6.2.2 nathanw */
1972 1.6.2.2 nathanw break;
1973 1.6.2.2 nathanw
1974 1.6.2.2 nathanw case SCSI_DISCONNECT:
1975 1.6.2.2 nathanw if (state->flags & DISCONN)
1976 1.6.2.2 nathanw goto abort;
1977 1.6.2.2 nathanw state->flags |= DISCONN;
1978 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1979 1.6.2.2 nathanw readback(regs->asc_cmd);
1980 1.6.2.2 nathanw asc->script = &asc_scripts[SCRIPT_DISCONNECT];
1981 1.6.2.2 nathanw return (0);
1982 1.6.2.2 nathanw
1983 1.6.2.2 nathanw default:
1984 1.6.2.2 nathanw printf("%s: SCSI device %d: rejecting message 0x%x\n",
1985 1.6.2.2 nathanw asc->sc_dev.dv_xname, asc->target, msg);
1986 1.6.2.2 nathanw reject:
1987 1.6.2.2 nathanw /* request a message out before acknowledging this message */
1988 1.6.2.2 nathanw state->msg_out = SCSI_MESSAGE_REJECT;
1989 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_SET_ATN;
1990 1.6.2.2 nathanw readback(regs->asc_cmd);
1991 1.6.2.2 nathanw }
1992 1.6.2.2 nathanw
1993 1.6.2.2 nathanw done:
1994 1.6.2.2 nathanw /* return to original script */
1995 1.6.2.2 nathanw regs->asc_cmd = ASC_CMD_MSG_ACPT;
1996 1.6.2.2 nathanw readback(regs->asc_cmd);
1997 1.6.2.2 nathanw if (!state->script) {
1998 1.6.2.2 nathanw abort:
1999 1.6.2.2 nathanw #ifdef DEBUG
2000 1.6.2.2 nathanw asc_DumpLog("asc_msg_in");
2001 1.6.2.2 nathanw #endif
2002 1.6.2.2 nathanw panic("asc_msg_in");
2003 1.6.2.2 nathanw }
2004 1.6.2.2 nathanw asc->script = state->script;
2005 1.6.2.2 nathanw state->script = (script_t *)0;
2006 1.6.2.2 nathanw return (0);
2007 1.6.2.2 nathanw }
2008 1.6.2.2 nathanw
2009 1.6.2.2 nathanw /* ARGSUSED */
2010 1.6.2.2 nathanw static int
2011 1.6.2.2 nathanw asc_disconnect(asc, status, ss, ir)
2012 1.6.2.2 nathanw asc_softc_t asc;
2013 1.6.2.2 nathanw int status, ss, ir;
2014 1.6.2.2 nathanw {
2015 1.6.2.2 nathanw #ifdef DIAGNOSTIC
2016 1.6.2.2 nathanw if (!(asc->st[asc->target].flags & DISCONN)) {
2017 1.6.2.2 nathanw printf("asc_disconnect: device %d: DISCONN not set!\n",
2018 1.6.2.2 nathanw asc->target);
2019 1.6.2.2 nathanw }
2020 1.6.2.2 nathanw #endif /* DIAGNOSTIC */
2021 1.6.2.2 nathanw asc->target = -1;
2022 1.6.2.2 nathanw asc->state = ASC_STATE_RESEL;
2023 1.6.2.2 nathanw return (1);
2024 1.6.2.2 nathanw }
2025 1.6.2.2 nathanw
2026 1.6.2.2 nathanw #ifdef DEBUG
2027 1.6.2.2 nathanw /*
2028 1.6.2.2 nathanw * Dump the log buffer.
2029 1.6.2.2 nathanw */
2030 1.6.2.2 nathanw static void
2031 1.6.2.2 nathanw asc_DumpLog(str)
2032 1.6.2.2 nathanw char *str;
2033 1.6.2.2 nathanw {
2034 1.6.2.2 nathanw register struct asc_log *lp;
2035 1.6.2.2 nathanw register u_int status;
2036 1.6.2.2 nathanw
2037 1.6.2.2 nathanw printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
2038 1.6.2.2 nathanw asc_debug_bn, asc_debug_sz);
2039 1.6.2.2 nathanw lp = asc_logp;
2040 1.6.2.2 nathanw do {
2041 1.6.2.2 nathanw status = lp->status;
2042 1.6.2.2 nathanw printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n",
2043 1.6.2.2 nathanw status >> 24,
2044 1.6.2.2 nathanw lp->target,
2045 1.6.2.2 nathanw (status >> 16) & 0xFF,
2046 1.6.2.2 nathanw (status >> 8) & 0xFF,
2047 1.6.2.2 nathanw status & 0XFF,
2048 1.6.2.2 nathanw lp->state,
2049 1.6.2.2 nathanw asc_scripts[lp->state].condition,
2050 1.6.2.2 nathanw lp->msg, lp->resid);
2051 1.6.2.2 nathanw if (++lp >= &asc_log[NLOG])
2052 1.6.2.2 nathanw lp = asc_log;
2053 1.6.2.2 nathanw } while (lp != asc_logp);
2054 1.6.2.2 nathanw }
2055 1.6.2.2 nathanw #endif /* DEBUG */
2056