aic7xxx.seq revision 1.13 1 1.13 wiz /* $NetBSD: aic7xxx.seq,v 1.13 2001/08/20 12:00:52 wiz Exp $ */
2 1.3 thorpej
3 1.11 fvdl /*
4 1.11 fvdl * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
5 1.2 mycroft *
6 1.11 fvdl * Copyright (c) 1994-2000 Justin Gibbs.
7 1.11 fvdl * All rights reserved.
8 1.2 mycroft *
9 1.11 fvdl * Redistribution and use in source and binary forms, with or without
10 1.11 fvdl * modification, are permitted provided that the following conditions
11 1.11 fvdl * are met:
12 1.11 fvdl * 1. Redistributions of source code must retain the above copyright
13 1.11 fvdl * notice, this list of conditions, and the following disclaimer,
14 1.11 fvdl * without modification.
15 1.11 fvdl * 2. The name of the author may not be used to endorse or promote products
16 1.11 fvdl * derived from this software without specific prior written permission.
17 1.2 mycroft *
18 1.11 fvdl * Alternatively, this software may be distributed under the terms of the
19 1.11 fvdl * the GNU Public License ("GPL").
20 1.2 mycroft *
21 1.11 fvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 1.11 fvdl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.11 fvdl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.11 fvdl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25 1.11 fvdl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.11 fvdl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 1.11 fvdl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.11 fvdl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 1.11 fvdl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 1.11 fvdl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 1.11 fvdl * SUCH DAMAGE.
32 1.2 mycroft *
33 1.11 fvdl * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.94 2000/02/09 21:25:00 gibbs Exp $
34 1.11 fvdl */
35 1.2 mycroft
36 1.2 mycroft /*
37 1.11 fvdl * #ifdef __NetBSD__
38 1.2 mycroft */
39 1.11 fvdl #include <dev/microcode/aic7xxx/aic7xxx.reg>
40 1.11 fvdl #include <dev/scsipi/scsi_message.h>
41 1.11 fvdl /*
42 1.11 fvdl * Assembler can't handle ifdef.
43 1.11 fvdl *
44 1.11 fvdl * #else
45 1.11 fvdl * #include <dev/aic7xxx/aic7xxx.reg>
46 1.11 fvdl * #include <cam/scsi/scsi_message.h>
47 1.11 fvdl * #endif
48 1.11 fvdl */
49 1.2 mycroft
50 1.11 fvdl /*
51 1.11 fvdl * A few words on the waiting SCB list:
52 1.11 fvdl * After starting the selection hardware, we check for reconnecting targets
53 1.2 mycroft * as well as for our selection to complete just in case the reselection wins
54 1.2 mycroft * bus arbitration. The problem with this is that we must keep track of the
55 1.2 mycroft * SCB that we've already pulled from the QINFIFO and started the selection
56 1.2 mycroft * on just in case the reselection wins so that we can retry the selection at
57 1.2 mycroft * a later time. This problem cannot be resolved by holding a single entry
58 1.2 mycroft * in scratch ram since a reconnecting target can request sense and this will
59 1.2 mycroft * create yet another SCB waiting for selection. The solution used here is to
60 1.2 mycroft * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
61 1.11 fvdl * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes,
62 1.11 fvdl * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to
63 1.11 fvdl * this list everytime a request sense occurs or after completing a non-tagged
64 1.11 fvdl * command for which a second SCB has been queued. The sequencer will
65 1.11 fvdl * automatically consume the entries.
66 1.2 mycroft */
67 1.2 mycroft
68 1.2 mycroft reset:
69 1.11 fvdl clr SCSISIGO; /* De-assert BSY */
70 1.11 fvdl mvi MSG_OUT, MSG_NOOP; /* No message to send */
71 1.11 fvdl and SXFRCTL1, ~BITBUCKET;
72 1.11 fvdl /* Always allow reselection */
73 1.11 fvdl and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
74 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
75 1.11 fvdl /* Ensure that no DMA operations are in progress */
76 1.11 fvdl clr CCSGCTL;
77 1.11 fvdl clr CCSCBCTL;
78 1.11 fvdl }
79 1.11 fvdl
80 1.1 mycroft poll_for_work:
81 1.11 fvdl call clear_target_state;
82 1.11 fvdl and SXFRCTL0, ~SPIOEN;
83 1.11 fvdl if ((ahc->features & AHC_QUEUE_REGS) == 0) {
84 1.11 fvdl mov A, QINPOS;
85 1.11 fvdl }
86 1.11 fvdl poll_for_work_loop:
87 1.11 fvdl if ((ahc->features & AHC_QUEUE_REGS) == 0) {
88 1.11 fvdl and SEQCTL, ~PAUSEDIS;
89 1.11 fvdl }
90 1.11 fvdl test SSTAT0, SELDO|SELDI jnz selection;
91 1.11 fvdl test SCSISEQ, ENSELO jnz poll_for_work;
92 1.11 fvdl if ((ahc->features & AHC_TWIN) != 0) {
93 1.11 fvdl /*
94 1.11 fvdl * Twin channel devices cannot handle things like SELTO
95 1.11 fvdl * interrupts on the "background" channel. So, if we
96 1.11 fvdl * are selecting, keep polling the current channel util
97 1.11 fvdl * either a selection or reselection occurs.
98 1.11 fvdl */
99 1.11 fvdl xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
100 1.11 fvdl test SSTAT0, SELDO|SELDI jnz selection;
101 1.11 fvdl test SCSISEQ, ENSELO jnz poll_for_work;
102 1.11 fvdl xor SBLKCTL,SELBUSB; /* Toggle back */
103 1.11 fvdl }
104 1.11 fvdl cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
105 1.11 fvdl test_queue:
106 1.11 fvdl /* Has the driver posted any work for us? */
107 1.11 fvdl if ((ahc->features & AHC_QUEUE_REGS) != 0) {
108 1.11 fvdl test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
109 1.11 fvdl mov NONE, SNSCB_QOFF;
110 1.11 fvdl inc QINPOS;
111 1.11 fvdl } else {
112 1.11 fvdl or SEQCTL, PAUSEDIS;
113 1.11 fvdl cmp KERNEL_QINPOS, A je poll_for_work_loop;
114 1.11 fvdl inc QINPOS;
115 1.11 fvdl and SEQCTL, ~PAUSEDIS;
116 1.11 fvdl }
117 1.2 mycroft
118 1.2 mycroft /*
119 1.2 mycroft * We have at least one queued SCB now and we don't have any
120 1.11 fvdl * SCBs in the list of SCBs awaiting selection. If we have
121 1.11 fvdl * any SCBs available for use, pull the tag from the QINFIFO
122 1.11 fvdl * and get to work on it.
123 1.11 fvdl */
124 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) != 0) {
125 1.11 fvdl mov ALLZEROS call get_free_or_disc_scb;
126 1.11 fvdl }
127 1.11 fvdl
128 1.11 fvdl dequeue_scb:
129 1.11 fvdl add A, -1, QINPOS;
130 1.11 fvdl mvi QINFIFO_OFFSET call fetch_byte;
131 1.11 fvdl
132 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) == 0) {
133 1.11 fvdl /* In the non-paging case, the SCBID == hardware SCB index */
134 1.11 fvdl mov SCBPTR, RETURN_2;
135 1.11 fvdl }
136 1.11 fvdl dma_queued_scb:
137 1.11 fvdl /*
138 1.11 fvdl * DMA the SCB from host ram into the current SCB location.
139 1.11 fvdl */
140 1.11 fvdl mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
141 1.11 fvdl mov RETURN_2 call dma_scb;
142 1.11 fvdl
143 1.11 fvdl /*
144 1.11 fvdl * Preset the residual fields in case we never go through a data phase.
145 1.11 fvdl * This isn't done by the host so we can avoid a DMA to clear these
146 1.11 fvdl * fields for the normal case of I/O that completes without underrun
147 1.11 fvdl * or overrun conditions.
148 1.11 fvdl */
149 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
150 1.11 fvdl bmov SCB_RESID_DCNT, SCB_DATACNT, 3;
151 1.11 fvdl } else {
152 1.11 fvdl mov SCB_RESID_DCNT[0],SCB_DATACNT[0];
153 1.11 fvdl mov SCB_RESID_DCNT[1],SCB_DATACNT[1];
154 1.11 fvdl mov SCB_RESID_DCNT[2],SCB_DATACNT[2];
155 1.11 fvdl }
156 1.11 fvdl mov SCB_RESID_SGCNT, SCB_SGCOUNT;
157 1.1 mycroft
158 1.1 mycroft start_scb:
159 1.11 fvdl /*
160 1.11 fvdl * Place us on the waiting list in case our selection
161 1.11 fvdl * doesn't win during bus arbitration.
162 1.11 fvdl */
163 1.11 fvdl mov SCB_NEXT,WAITING_SCBH;
164 1.11 fvdl mov WAITING_SCBH, SCBPTR;
165 1.11 fvdl start_waiting:
166 1.11 fvdl /*
167 1.11 fvdl * Pull the first entry off of the waiting SCB list.
168 1.11 fvdl */
169 1.11 fvdl mov SCBPTR, WAITING_SCBH;
170 1.11 fvdl call start_selection;
171 1.11 fvdl jmp poll_for_work;
172 1.1 mycroft
173 1.2 mycroft start_selection:
174 1.11 fvdl if ((ahc->features & AHC_TWIN) != 0) {
175 1.11 fvdl and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
176 1.11 fvdl and A,SELBUSB,SCB_TCL; /* Get new channel bit */
177 1.11 fvdl or SINDEX,A;
178 1.11 fvdl mov SBLKCTL,SINDEX; /* select channel */
179 1.11 fvdl }
180 1.11 fvdl initialize_scsiid:
181 1.11 fvdl mov SINDEX, SCSISEQ_TEMPLATE;
182 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
183 1.11 fvdl test SCB_CONTROL, TARGET_SCB jz . + 4;
184 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
185 1.11 fvdl mov SCSIID_ULTRA2, SCB_CMDPTR[2];
186 1.11 fvdl } else {
187 1.11 fvdl mov SCSIID, SCB_CMDPTR[2];
188 1.11 fvdl }
189 1.11 fvdl or SINDEX, TEMODE;
190 1.11 fvdl jmp initialize_scsiid_fini;
191 1.11 fvdl }
192 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
193 1.11 fvdl and A, TID, SCB_TCL; /* Get target ID */
194 1.11 fvdl and SCSIID_ULTRA2, OID; /* Clear old target */
195 1.11 fvdl or SCSIID_ULTRA2, A;
196 1.11 fvdl } else {
197 1.11 fvdl and A, TID, SCB_TCL; /* Get target ID */
198 1.11 fvdl and SCSIID, OID; /* Clear old target */
199 1.11 fvdl or SCSIID, A;
200 1.11 fvdl }
201 1.11 fvdl initialize_scsiid_fini:
202 1.11 fvdl mov SCSISEQ, SINDEX ret;
203 1.11 fvdl
204 1.11 fvdl /*
205 1.11 fvdl * Initialize transfer settings and clear the SCSI channel.
206 1.11 fvdl * SINDEX should contain any additional bit's the client wants
207 1.11 fvdl * set in SXFRCTL0. We also assume that the current SCB is
208 1.11 fvdl * a valid SCB for the target we wish to talk to.
209 1.11 fvdl */
210 1.11 fvdl initialize_channel:
211 1.11 fvdl or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
212 1.11 fvdl set_transfer_settings:
213 1.11 fvdl if ((ahc->features & AHC_ULTRA) != 0) {
214 1.11 fvdl test SCB_CONTROL, ULTRAENB jz . + 2;
215 1.11 fvdl or SXFRCTL0, FAST20;
216 1.11 fvdl }
217 1.2 mycroft /*
218 1.11 fvdl * Initialize SCSIRATE with the appropriate value for this target.
219 1.2 mycroft */
220 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
221 1.11 fvdl bmov SCSIRATE, SCB_SCSIRATE, 2 ret;
222 1.11 fvdl } else {
223 1.11 fvdl mov SCSIRATE, SCB_SCSIRATE ret;
224 1.11 fvdl }
225 1.11 fvdl
226 1.11 fvdl selection:
227 1.11 fvdl test SSTAT0,SELDO jnz select_out;
228 1.11 fvdl mvi CLRSINT0, CLRSELDI;
229 1.11 fvdl select_in:
230 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
231 1.11 fvdl if ((ahc->flags & AHC_INITIATORMODE) != 0) {
232 1.11 fvdl test SSTAT0, TARGET jz initiator_reselect;
233 1.11 fvdl }
234 1.11 fvdl
235 1.11 fvdl /*
236 1.11 fvdl * We've just been selected. Assert BSY and
237 1.11 fvdl * setup the phase for receiving messages
238 1.11 fvdl * from the target.
239 1.11 fvdl */
240 1.11 fvdl mvi SCSISIGO, P_MESGOUT|BSYO;
241 1.11 fvdl mvi CLRSINT1, CLRBUSFREE;
242 1.11 fvdl
243 1.11 fvdl /*
244 1.11 fvdl * Setup the DMA for sending the identify and
245 1.11 fvdl * command information.
246 1.11 fvdl */
247 1.11 fvdl or SEQ_FLAGS, CMDPHASE_PENDING;
248 1.11 fvdl
249 1.11 fvdl mov A, TQINPOS;
250 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
251 1.11 fvdl mvi DINDEX, CCHADDR;
252 1.11 fvdl mvi TMODE_CMDADDR call set_32byte_addr;
253 1.11 fvdl mvi CCSCBCTL, CCSCBRESET;
254 1.11 fvdl } else {
255 1.11 fvdl mvi DINDEX, HADDR;
256 1.11 fvdl mvi TMODE_CMDADDR call set_32byte_addr;
257 1.11 fvdl mvi DFCNTRL, FIFORESET;
258 1.11 fvdl }
259 1.11 fvdl
260 1.11 fvdl /* Initiator that selected us */
261 1.11 fvdl and SAVED_TCL, SELID_MASK, SELID;
262 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
263 1.11 fvdl mov CCSCBRAM, SAVED_TCL;
264 1.11 fvdl } else {
265 1.11 fvdl mov DFDAT, SAVED_TCL;
266 1.11 fvdl }
267 1.11 fvdl
268 1.11 fvdl /* The Target ID we were selected at */
269 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
270 1.11 fvdl if ((ahc->features & AHC_MULTI_TID) != 0) {
271 1.11 fvdl and CCSCBRAM, OID, TARGIDIN;
272 1.11 fvdl } else if ((ahc->features & AHC_ULTRA2) != 0) {
273 1.11 fvdl and CCSCBRAM, OID, SCSIID_ULTRA2;
274 1.11 fvdl } else {
275 1.11 fvdl and CCSCBRAM, OID, SCSIID;
276 1.11 fvdl }
277 1.11 fvdl } else {
278 1.11 fvdl if ((ahc->features & AHC_MULTI_TID) != 0) {
279 1.11 fvdl and DFDAT, OID, TARGIDIN;
280 1.11 fvdl } else if ((ahc->features & AHC_ULTRA2) != 0) {
281 1.11 fvdl and DFDAT, OID, SCSIID_ULTRA2;
282 1.11 fvdl } else {
283 1.11 fvdl and DFDAT, OID, SCSIID;
284 1.11 fvdl }
285 1.11 fvdl }
286 1.11 fvdl
287 1.11 fvdl /* No tag yet */
288 1.11 fvdl mvi INITIATOR_TAG, SCB_LIST_NULL;
289 1.11 fvdl
290 1.11 fvdl /*
291 1.11 fvdl * If ATN isn't asserted, the target isn't interested
292 1.11 fvdl * in talking to us. Go directly to bus free.
293 1.11 fvdl */
294 1.11 fvdl test SCSISIGI, ATNI jz target_busfree;
295 1.11 fvdl
296 1.11 fvdl /*
297 1.11 fvdl * Watch ATN closely now as we pull in messages from the
298 1.11 fvdl * initiator. We follow the guidlines from section 6.5
299 1.11 fvdl * of the SCSI-2 spec for what messages are allowed when.
300 1.11 fvdl */
301 1.11 fvdl call target_inb;
302 1.11 fvdl
303 1.11 fvdl /*
304 1.11 fvdl * Our first message must be one of IDENTIFY, ABORT, or
305 1.11 fvdl * BUS_DEVICE_RESET.
306 1.11 fvdl */
307 1.11 fvdl /* XXX May need to be more lax here for older initiators... */
308 1.11 fvdl test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
309 1.11 fvdl /* Store for host */
310 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
311 1.11 fvdl mov CCSCBRAM, DINDEX;
312 1.11 fvdl } else {
313 1.11 fvdl mov DFDAT, DINDEX;
314 1.11 fvdl }
315 1.11 fvdl
316 1.11 fvdl /* Remember for disconnection decision */
317 1.11 fvdl test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
318 1.11 fvdl /* XXX Honor per target settings too */
319 1.11 fvdl or SEQ_FLAGS, NO_DISCONNECT;
320 1.11 fvdl
321 1.11 fvdl test SCSISIGI, ATNI jz ident_messages_done;
322 1.11 fvdl call target_inb;
323 1.11 fvdl /*
324 1.11 fvdl * If this is a tagged request, the tagged message must
325 1.11 fvdl * immediately follow the identify. We test for a valid
326 1.11 fvdl * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
327 1.11 fvdl * < MSG_IGN_WIDE_RESIDUE.
328 1.11 fvdl */
329 1.11 fvdl add A, -MSG_SIMPLE_Q_TAG, DINDEX;
330 1.11 fvdl jnc ident_messages_done;
331 1.11 fvdl add A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
332 1.11 fvdl jc ident_messages_done;
333 1.11 fvdl /* Store for host */
334 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
335 1.11 fvdl mov CCSCBRAM, DINDEX;
336 1.11 fvdl } else {
337 1.11 fvdl mov DFDAT, DINDEX;
338 1.11 fvdl }
339 1.11 fvdl
340 1.11 fvdl /*
341 1.11 fvdl * If the initiator doesn't feel like providing a tag number,
342 1.11 fvdl * we've got a failed selection and must transition to bus
343 1.11 fvdl * free.
344 1.11 fvdl */
345 1.11 fvdl test SCSISIGI, ATNI jz target_busfree;
346 1.11 fvdl
347 1.11 fvdl /*
348 1.11 fvdl * Store the tag for the host.
349 1.11 fvdl */
350 1.11 fvdl call target_inb;
351 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
352 1.11 fvdl mov CCSCBRAM, DINDEX;
353 1.11 fvdl } else {
354 1.11 fvdl mov DFDAT, DINDEX;
355 1.11 fvdl }
356 1.11 fvdl mov INITIATOR_TAG, DINDEX;
357 1.11 fvdl jmp ident_messages_done;
358 1.11 fvdl
359 1.11 fvdl /*
360 1.11 fvdl * Pushed message loop to allow the kernel to
361 1.11 fvdl * run it's own target mode message state engine.
362 1.11 fvdl */
363 1.11 fvdl host_target_message_loop:
364 1.11 fvdl mvi INTSTAT, HOST_MSG_LOOP;
365 1.11 fvdl nop;
366 1.11 fvdl cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop;
367 1.11 fvdl test SSTAT0, SPIORDY jz .;
368 1.11 fvdl jmp host_target_message_loop;
369 1.11 fvdl
370 1.11 fvdl ident_messages_done:
371 1.11 fvdl /* If ring buffer is full, return busy or queue full */
372 1.11 fvdl mov A, KERNEL_TQINPOS;
373 1.11 fvdl cmp TQINPOS, A jne tqinfifo_has_space;
374 1.11 fvdl mvi P_STATUS|BSYO call change_phase;
375 1.11 fvdl cmp INITIATOR_TAG, SCB_LIST_NULL je . + 3;
376 1.11 fvdl mvi STATUS_QUEUE_FULL call target_outb;
377 1.11 fvdl jmp target_busfree_wait;
378 1.11 fvdl mvi STATUS_BUSY call target_outb;
379 1.11 fvdl jmp target_busfree_wait;
380 1.11 fvdl tqinfifo_has_space:
381 1.11 fvdl /* Terminate the ident list */
382 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
383 1.11 fvdl mvi CCSCBRAM, SCB_LIST_NULL;
384 1.11 fvdl } else {
385 1.11 fvdl mvi DFDAT, SCB_LIST_NULL;
386 1.11 fvdl }
387 1.11 fvdl or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
388 1.11 fvdl test SCSISIGI, ATNI jnz target_mesgout_pending_msg;
389 1.11 fvdl jmp target_ITloop;
390 1.11 fvdl
391 1.11 fvdl /*
392 1.11 fvdl * We carefully toggle SPIOEN to allow us to return the
393 1.11 fvdl * message byte we receive so it can be checked prior to
394 1.11 fvdl * driving REQ on the bus for the next byte.
395 1.11 fvdl */
396 1.11 fvdl target_inb:
397 1.11 fvdl /*
398 1.11 fvdl * Drive REQ on the bus by enabling SCSI PIO.
399 1.11 fvdl */
400 1.11 fvdl or SXFRCTL0, SPIOEN;
401 1.11 fvdl /* Wait for the byte */
402 1.11 fvdl test SSTAT0, SPIORDY jz .;
403 1.11 fvdl /* Prevent our read from triggering another REQ */
404 1.11 fvdl and SXFRCTL0, ~SPIOEN;
405 1.11 fvdl /* Save latched contents */
406 1.11 fvdl mov DINDEX, SCSIDATL ret;
407 1.11 fvdl }
408 1.2 mycroft
409 1.11 fvdl if ((ahc->flags & AHC_INITIATORMODE) != 0) {
410 1.2 mycroft /*
411 1.2 mycroft * Reselection has been initiated by a target. Make a note that we've been
412 1.11 fvdl * reselected, but haven't seen an IDENTIFY message from the target yet.
413 1.2 mycroft */
414 1.11 fvdl initiator_reselect:
415 1.11 fvdl /* XXX test for and handle ONE BIT condition */
416 1.11 fvdl and SAVED_TCL, SELID_MASK, SELID;
417 1.11 fvdl if ((ahc->features & AHC_TWIN) != 0) {
418 1.11 fvdl test SBLKCTL, SELBUSB jz . + 2;
419 1.11 fvdl or SAVED_TCL, SELBUSB;
420 1.11 fvdl }
421 1.11 fvdl or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
422 1.11 fvdl mvi CLRSINT1,CLRBUSFREE;
423 1.11 fvdl or SIMODE1, ENBUSFREE; /*
424 1.11 fvdl * We aren't expecting a
425 1.11 fvdl * bus free, so interrupt
426 1.11 fvdl * the kernel driver if it
427 1.11 fvdl * happens.
428 1.11 fvdl */
429 1.11 fvdl jmp ITloop;
430 1.11 fvdl }
431 1.1 mycroft
432 1.2 mycroft /*
433 1.11 fvdl * After the selection, remove this SCB from the "waiting SCB"
434 1.2 mycroft * list. This is achieved by simply moving our "next" pointer into
435 1.2 mycroft * WAITING_SCBH. Our next pointer will be set to null the next time this
436 1.2 mycroft * SCB is used, so don't bother with it now.
437 1.2 mycroft */
438 1.11 fvdl select_out:
439 1.11 fvdl /* Turn off the selection hardware */
440 1.11 fvdl and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
441 1.11 fvdl mvi CLRSINT0, CLRSELDO;
442 1.11 fvdl mov SCBPTR, WAITING_SCBH;
443 1.11 fvdl mov WAITING_SCBH,SCB_NEXT;
444 1.11 fvdl mov SAVED_TCL, SCB_TCL;
445 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
446 1.11 fvdl test SSTAT0, TARGET jz initiator_select;
447 1.11 fvdl
448 1.11 fvdl /*
449 1.11 fvdl * We've just re-selected an initiator.
450 1.11 fvdl * Assert BSY and setup the phase for
451 1.11 fvdl * sending our identify messages.
452 1.11 fvdl */
453 1.11 fvdl mvi P_MESGIN|BSYO call change_phase;
454 1.11 fvdl mvi CLRSINT1,CLRBUSFREE;
455 1.11 fvdl
456 1.11 fvdl /*
457 1.11 fvdl * Start out with a simple identify message.
458 1.11 fvdl */
459 1.11 fvdl and A, LID, SCB_TCL;
460 1.11 fvdl or A, MSG_IDENTIFYFLAG call target_outb;
461 1.11 fvdl
462 1.11 fvdl /*
463 1.11 fvdl * If we are the result of a tagged command, send
464 1.11 fvdl * a simple Q tag and the tag id.
465 1.11 fvdl */
466 1.11 fvdl test SCB_CONTROL, TAG_ENB jz . + 3;
467 1.11 fvdl mvi MSG_SIMPLE_Q_TAG call target_outb;
468 1.11 fvdl mov SCB_INITIATOR_TAG call target_outb;
469 1.11 fvdl mov INITIATOR_TAG, SCB_INITIATOR_TAG;
470 1.11 fvdl target_synccmd:
471 1.11 fvdl /*
472 1.11 fvdl * Now determine what phases the host wants us
473 1.11 fvdl * to go through.
474 1.11 fvdl */
475 1.11 fvdl mov SEQ_FLAGS, SCB_TARGET_PHASES;
476 1.11 fvdl
477 1.11 fvdl
478 1.11 fvdl target_ITloop:
479 1.11 fvdl /*
480 1.11 fvdl * Start honoring ATN signals now that
481 1.11 fvdl * we properly identified ourselves.
482 1.11 fvdl */
483 1.11 fvdl test SCSISIGI, ATNI jnz target_mesgout;
484 1.11 fvdl test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase;
485 1.11 fvdl test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase;
486 1.11 fvdl test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase;
487 1.11 fvdl
488 1.11 fvdl /*
489 1.11 fvdl * No more work to do. Either disconnect or not depending
490 1.11 fvdl * on the state of NO_DISCONNECT.
491 1.11 fvdl */
492 1.11 fvdl test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect;
493 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) != 0) {
494 1.11 fvdl mov ALLZEROS call get_free_or_disc_scb;
495 1.11 fvdl }
496 1.11 fvdl mov RETURN_1, ALLZEROS;
497 1.11 fvdl call complete_target_cmd;
498 1.11 fvdl cmp RETURN_1, CONT_MSG_LOOP jne .;
499 1.11 fvdl mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
500 1.11 fvdl mov SCB_TAG call dma_scb;
501 1.11 fvdl jmp target_synccmd;
502 1.11 fvdl
503 1.11 fvdl target_mesgout:
504 1.11 fvdl mvi SCSISIGO, P_MESGOUT|BSYO;
505 1.11 fvdl call target_inb;
506 1.11 fvdl /* Local Processing goes here... */
507 1.11 fvdl target_mesgout_pending_msg:
508 1.11 fvdl jmp host_target_message_loop;
509 1.11 fvdl
510 1.11 fvdl target_disconnect:
511 1.11 fvdl mvi P_MESGIN|BSYO call change_phase;
512 1.11 fvdl test SEQ_FLAGS, DPHASE jz . + 2;
513 1.11 fvdl mvi MSG_SAVEDATAPOINTER call target_outb;
514 1.11 fvdl mvi MSG_DISCONNECT call target_outb;
515 1.11 fvdl
516 1.11 fvdl target_busfree_wait:
517 1.13 wiz /* Wait for preceding I/O session to complete. */
518 1.11 fvdl test SCSISIGI, ACKI jnz .;
519 1.11 fvdl target_busfree:
520 1.11 fvdl clr SCSISIGO;
521 1.11 fvdl mvi LASTPHASE, P_BUSFREE;
522 1.11 fvdl call complete_target_cmd;
523 1.11 fvdl jmp poll_for_work;
524 1.11 fvdl
525 1.11 fvdl target_cmdphase:
526 1.11 fvdl mvi P_COMMAND|BSYO call change_phase;
527 1.11 fvdl call target_inb;
528 1.11 fvdl mov A, DINDEX;
529 1.11 fvdl /* Store for host */
530 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
531 1.11 fvdl mov CCSCBRAM, A;
532 1.11 fvdl } else {
533 1.11 fvdl mov DFDAT, A;
534 1.11 fvdl }
535 1.11 fvdl
536 1.11 fvdl /*
537 1.11 fvdl * Determine the number of bytes to read
538 1.11 fvdl * based on the command group code via table lookup.
539 1.11 fvdl * We reuse the first 8 bytes of the TARG_SCSIRATE
540 1.11 fvdl * BIOS array for this table. Count is one less than
541 1.11 fvdl * the total for the command since we've already fetched
542 1.11 fvdl * the first byte.
543 1.11 fvdl */
544 1.11 fvdl shr A, CMD_GROUP_CODE_SHIFT;
545 1.11 fvdl add SINDEX, TARG_SCSIRATE, A;
546 1.11 fvdl mov A, SINDIR;
547 1.11 fvdl
548 1.11 fvdl test A, 0xFF jz command_phase_done;
549 1.11 fvdl command_loop:
550 1.11 fvdl or SXFRCTL0, SPIOEN;
551 1.11 fvdl test SSTAT0, SPIORDY jz .;
552 1.11 fvdl cmp A, 1 jne . + 2;
553 1.11 fvdl and SXFRCTL0, ~SPIOEN; /* Last Byte */
554 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
555 1.11 fvdl mov CCSCBRAM, SCSIDATL;
556 1.11 fvdl } else {
557 1.11 fvdl mov DFDAT, SCSIDATL;
558 1.11 fvdl }
559 1.11 fvdl dec A;
560 1.11 fvdl test A, 0xFF jnz command_loop;
561 1.11 fvdl
562 1.11 fvdl command_phase_done:
563 1.11 fvdl and SEQ_FLAGS, ~CMDPHASE_PENDING;
564 1.11 fvdl jmp target_ITloop;
565 1.11 fvdl
566 1.11 fvdl target_dphase:
567 1.11 fvdl /*
568 1.11 fvdl * Data direction flags are from the
569 1.11 fvdl * perspective of the initiator.
570 1.11 fvdl */
571 1.11 fvdl test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4;
572 1.11 fvdl mvi LASTPHASE, P_DATAOUT;
573 1.11 fvdl mvi P_DATAIN|BSYO call change_phase;
574 1.11 fvdl jmp . + 3;
575 1.11 fvdl mvi LASTPHASE, P_DATAIN;
576 1.11 fvdl mvi P_DATAOUT|BSYO call change_phase;
577 1.11 fvdl mov ALLZEROS call initialize_channel;
578 1.11 fvdl jmp p_data;
579 1.11 fvdl
580 1.11 fvdl target_sphase:
581 1.11 fvdl mvi P_STATUS|BSYO call change_phase;
582 1.11 fvdl mvi LASTPHASE, P_STATUS;
583 1.11 fvdl mov SCB_TARGET_STATUS call target_outb;
584 1.11 fvdl /* XXX Watch for ATN or parity errors??? */
585 1.11 fvdl mvi SCSISIGO, P_MESGIN|BSYO;
586 1.11 fvdl /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
587 1.11 fvdl mov ALLZEROS call target_outb;
588 1.11 fvdl jmp target_busfree_wait;
589 1.11 fvdl
590 1.11 fvdl complete_target_cmd:
591 1.11 fvdl test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2;
592 1.11 fvdl mov SCB_TAG jmp complete_post;
593 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
594 1.11 fvdl /* Set the valid byte */
595 1.11 fvdl mvi CCSCBADDR, 24;
596 1.11 fvdl mov CCSCBRAM, ALLONES;
597 1.11 fvdl mvi CCHCNT, 28;
598 1.11 fvdl or CCSCBCTL, CCSCBEN|CCSCBRESET;
599 1.11 fvdl test CCSCBCTL, CCSCBDONE jz .;
600 1.11 fvdl clr CCSCBCTL;
601 1.11 fvdl } else {
602 1.11 fvdl /* Set the valid byte */
603 1.11 fvdl or DFCNTRL, FIFORESET;
604 1.11 fvdl mvi DFWADDR, 3; /* Third 64bit word or byte 24 */
605 1.11 fvdl mov DFDAT, ALLONES;
606 1.11 fvdl mvi HCNT[0], 28;
607 1.11 fvdl clr HCNT[1];
608 1.11 fvdl clr HCNT[2];
609 1.11 fvdl or DFCNTRL, HDMAEN|FIFOFLUSH;
610 1.11 fvdl call dma_finish;
611 1.11 fvdl }
612 1.11 fvdl inc TQINPOS;
613 1.11 fvdl mvi INTSTAT,CMDCMPLT ret;
614 1.11 fvdl }
615 1.11 fvdl
616 1.11 fvdl if ((ahc->flags & AHC_INITIATORMODE) != 0) {
617 1.11 fvdl initiator_select:
618 1.11 fvdl mvi SPIOEN call initialize_channel;
619 1.11 fvdl
620 1.11 fvdl /*
621 1.11 fvdl * We aren't expecting a bus free, so interrupt
622 1.11 fvdl * the kernel driver if it happens.
623 1.11 fvdl */
624 1.11 fvdl mvi CLRSINT1,CLRBUSFREE;
625 1.11 fvdl or SIMODE1, ENBUSFREE;
626 1.11 fvdl
627 1.11 fvdl /*
628 1.11 fvdl * As soon as we get a successful selection, the target
629 1.11 fvdl * should go into the message out phase since we have ATN
630 1.11 fvdl * asserted.
631 1.11 fvdl */
632 1.11 fvdl mvi MSG_OUT, MSG_IDENTIFYFLAG;
633 1.11 fvdl or SEQ_FLAGS, IDENTIFY_SEEN;
634 1.2 mycroft
635 1.11 fvdl /*
636 1.11 fvdl * Main loop for information transfer phases. Wait for the
637 1.11 fvdl * target to assert REQ before checking MSG, C/D and I/O for
638 1.11 fvdl * the bus phase.
639 1.11 fvdl */
640 1.1 mycroft ITloop:
641 1.11 fvdl call phase_lock;
642 1.11 fvdl
643 1.11 fvdl mov A, LASTPHASE;
644 1.11 fvdl
645 1.11 fvdl test A, ~P_DATAIN jz p_data;
646 1.11 fvdl cmp A,P_COMMAND je p_command;
647 1.11 fvdl cmp A,P_MESGOUT je p_mesgout;
648 1.11 fvdl cmp A,P_STATUS je p_status;
649 1.11 fvdl cmp A,P_MESGIN je p_mesgin;
650 1.11 fvdl
651 1.11 fvdl mvi INTSTAT,BAD_PHASE;
652 1.11 fvdl jmp ITloop; /* Try reading the bus again. */
653 1.11 fvdl
654 1.11 fvdl await_busfree:
655 1.11 fvdl and SIMODE1, ~ENBUSFREE;
656 1.11 fvdl mov NONE, SCSIDATL; /* Ack the last byte */
657 1.11 fvdl and SXFRCTL0, ~SPIOEN;
658 1.11 fvdl test SSTAT1,REQINIT|BUSFREE jz .;
659 1.11 fvdl test SSTAT1, BUSFREE jnz poll_for_work;
660 1.11 fvdl mvi INTSTAT, BAD_PHASE;
661 1.11 fvdl }
662 1.11 fvdl
663 1.11 fvdl clear_target_state:
664 1.11 fvdl /*
665 1.11 fvdl * We assume that the kernel driver may reset us
666 1.11 fvdl * at any time, even in the middle of a DMA, so
667 1.11 fvdl * clear DFCNTRL too.
668 1.11 fvdl */
669 1.11 fvdl clr DFCNTRL;
670 1.1 mycroft
671 1.11 fvdl /*
672 1.11 fvdl * We don't know the target we will connect to,
673 1.11 fvdl * so default to narrow transfers to avoid
674 1.11 fvdl * parity problems.
675 1.11 fvdl */
676 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
677 1.11 fvdl bmov SCSIRATE, ALLZEROS, 2;
678 1.11 fvdl } else {
679 1.11 fvdl clr SCSIRATE;
680 1.11 fvdl and SXFRCTL0, ~(FAST20);
681 1.11 fvdl }
682 1.11 fvdl mvi LASTPHASE, P_BUSFREE;
683 1.11 fvdl /* clear target specific flags */
684 1.11 fvdl clr SEQ_FLAGS ret;
685 1.2 mycroft
686 1.2 mycroft /*
687 1.2 mycroft * If we re-enter the data phase after going through another phase, the
688 1.2 mycroft * STCNT may have been cleared, so restore it from the residual field.
689 1.2 mycroft */
690 1.2 mycroft data_phase_reinit:
691 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
692 1.11 fvdl /*
693 1.11 fvdl * The preload circuitry requires us to
694 1.11 fvdl * reload the address too, so pull it from
695 1.11 fvdl * the shaddow address.
696 1.11 fvdl */
697 1.11 fvdl bmov HADDR, SHADDR, 4;
698 1.11 fvdl bmov HCNT, SCB_RESID_DCNT, 3;
699 1.11 fvdl } else if ((ahc->features & AHC_CMD_CHAN) != 0) {
700 1.11 fvdl bmov STCNT, SCB_RESID_DCNT, 3;
701 1.11 fvdl } else {
702 1.11 fvdl mvi DINDEX, STCNT;
703 1.11 fvdl mvi SCB_RESID_DCNT call bcopy_3;
704 1.11 fvdl }
705 1.11 fvdl and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0];
706 1.11 fvdl jmp data_phase_loop;
707 1.11 fvdl
708 1.11 fvdl p_data:
709 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
710 1.11 fvdl mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
711 1.11 fvdl } else {
712 1.11 fvdl mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
713 1.11 fvdl }
714 1.11 fvdl test LASTPHASE, IOI jnz . + 2;
715 1.11 fvdl or DMAPARAMS, DIRECTION;
716 1.11 fvdl call assert; /*
717 1.11 fvdl * Ensure entering a data
718 1.11 fvdl * phase is okay - seen identify, etc.
719 1.2 mycroft */
720 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
721 1.11 fvdl mvi CCSGADDR, CCSGADDR_MAX;
722 1.11 fvdl }
723 1.11 fvdl test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
724 1.1 mycroft
725 1.11 fvdl /* We have seen a data phase */
726 1.11 fvdl or SEQ_FLAGS, DPHASE;
727 1.11 fvdl
728 1.11 fvdl /*
729 1.11 fvdl * Initialize the DMA address and counter from the SCB.
730 1.11 fvdl * Also set SG_COUNT and SG_NEXT in memory since we cannot
731 1.11 fvdl * modify the values in the SCB itself until we see a
732 1.11 fvdl * save data pointers message.
733 1.11 fvdl */
734 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
735 1.11 fvdl bmov HADDR, SCB_DATAPTR, 7;
736 1.11 fvdl } else {
737 1.11 fvdl mvi DINDEX, HADDR;
738 1.11 fvdl mvi SCB_DATAPTR call bcopy_7;
739 1.11 fvdl }
740 1.11 fvdl and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
741 1.11 fvdl
742 1.11 fvdl if ((ahc->features & AHC_ULTRA2) == 0) {
743 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
744 1.11 fvdl bmov STCNT, HCNT, 3;
745 1.11 fvdl } else {
746 1.11 fvdl call set_stcnt_from_hcnt;
747 1.11 fvdl }
748 1.11 fvdl }
749 1.11 fvdl
750 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
751 1.11 fvdl bmov SG_COUNT, SCB_SGCOUNT, 5;
752 1.11 fvdl } else {
753 1.11 fvdl mvi DINDEX, SG_COUNT;
754 1.11 fvdl mvi SCB_SGCOUNT call bcopy_5;
755 1.11 fvdl }
756 1.1 mycroft
757 1.2 mycroft data_phase_loop:
758 1.4 explorer /* Guard against overruns */
759 1.11 fvdl test SG_COUNT, 0xff jnz data_phase_inbounds;
760 1.4 explorer /*
761 1.4 explorer * Turn on 'Bit Bucket' mode, set the transfer count to
762 1.4 explorer * 16meg and let the target run until it changes phase.
763 1.4 explorer * When the transfer completes, notify the host that we
764 1.4 explorer * had an overrun.
765 1.4 explorer */
766 1.11 fvdl or SXFRCTL1,BITBUCKET;
767 1.11 fvdl and DMAPARAMS, ~(HDMAEN|SDMAEN);
768 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
769 1.11 fvdl bmov HCNT, ALLONES, 3;
770 1.11 fvdl } else if ((ahc->features & AHC_CMD_CHAN) != 0) {
771 1.11 fvdl bmov STCNT, ALLONES, 3;
772 1.11 fvdl } else {
773 1.11 fvdl mvi STCNT[0], 0xFF;
774 1.11 fvdl mvi STCNT[1], 0xFF;
775 1.11 fvdl mvi STCNT[2], 0xFF;
776 1.11 fvdl }
777 1.4 explorer data_phase_inbounds:
778 1.11 fvdl /* If we are the last SG block, tell the hardware. */
779 1.11 fvdl cmp SG_COUNT,0x01 jne data_phase_wideodd;
780 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
781 1.11 fvdl or SG_CACHEPTR, LAST_SEG;
782 1.11 fvdl } else {
783 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
784 1.11 fvdl test SSTAT0, TARGET jz . + 2;
785 1.11 fvdl test DMAPARAMS, DIRECTION jz data_phase_wideodd;
786 1.11 fvdl }
787 1.11 fvdl and DMAPARAMS, ~WIDEODD;
788 1.11 fvdl }
789 1.2 mycroft data_phase_wideodd:
790 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
791 1.11 fvdl mov SINDEX, ALLONES;
792 1.11 fvdl mov DFCNTRL, DMAPARAMS;
793 1.11 fvdl test SSTAT0, SDONE jnz .;/* Wait for preload to complete */
794 1.11 fvdl data_phase_dma_loop:
795 1.11 fvdl test SSTAT0, SDONE jnz data_phase_dma_done;
796 1.11 fvdl test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
797 1.11 fvdl } else {
798 1.11 fvdl mov DMAPARAMS call dma;
799 1.11 fvdl }
800 1.2 mycroft
801 1.11 fvdl data_phase_dma_done:
802 1.4 explorer /* Go tell the host about any overruns */
803 1.11 fvdl test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
804 1.4 explorer
805 1.11 fvdl /* See if we completed this segment */
806 1.11 fvdl test STCNT[0], 0xff jnz data_phase_finish;
807 1.11 fvdl test STCNT[1], 0xff jnz data_phase_finish;
808 1.11 fvdl test STCNT[2], 0xff jnz data_phase_finish;
809 1.2 mycroft
810 1.2 mycroft /*
811 1.2 mycroft * Advance the scatter-gather pointers if needed
812 1.2 mycroft */
813 1.2 mycroft sg_advance:
814 1.11 fvdl dec SG_COUNT; /* one less segment to go */
815 1.2 mycroft
816 1.11 fvdl test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
817 1.2 mycroft /*
818 1.2 mycroft * Load a struct scatter and set up the data address and length.
819 1.2 mycroft * If the working value of the SG count is nonzero, then
820 1.2 mycroft * we need to load a new set of values.
821 1.2 mycroft *
822 1.2 mycroft * This, like all DMA's, assumes little-endian host data storage.
823 1.2 mycroft */
824 1.2 mycroft sg_load:
825 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
826 1.11 fvdl /*
827 1.11 fvdl * Do we have any prefetch left???
828 1.11 fvdl */
829 1.11 fvdl cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
830 1.11 fvdl
831 1.11 fvdl /*
832 1.11 fvdl * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
833 1.11 fvdl */
834 1.11 fvdl add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
835 1.11 fvdl mvi A, CCSGADDR_MAX;
836 1.11 fvdl jc . + 2;
837 1.11 fvdl shl A, 3, SG_COUNT;
838 1.11 fvdl mov CCHCNT, A;
839 1.11 fvdl bmov CCHADDR, SG_NEXT, 4;
840 1.11 fvdl mvi CCSGCTL, CCSGEN|CCSGRESET;
841 1.11 fvdl test CCSGCTL, CCSGDONE jz .;
842 1.11 fvdl and CCSGCTL, ~CCSGEN;
843 1.11 fvdl test CCSGCTL, CCSGEN jnz .;
844 1.11 fvdl mvi CCSGCTL, CCSGRESET;
845 1.11 fvdl prefetched_segs_avail:
846 1.11 fvdl bmov HADDR, CCSGRAM, 8;
847 1.11 fvdl } else {
848 1.11 fvdl mvi DINDEX, HADDR;
849 1.11 fvdl mvi SG_NEXT call bcopy_4;
850 1.11 fvdl
851 1.11 fvdl mvi HCNT[0],SG_SIZEOF;
852 1.11 fvdl clr HCNT[1];
853 1.11 fvdl clr HCNT[2];
854 1.11 fvdl
855 1.11 fvdl or DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
856 1.11 fvdl
857 1.11 fvdl call dma_finish;
858 1.11 fvdl
859 1.11 fvdl /*
860 1.11 fvdl * Copy data from FIFO into SCB data pointer and data count.
861 1.11 fvdl * This assumes that the SG segments are of the form:
862 1.11 fvdl * struct ahc_dma_seg {
863 1.11 fvdl * u_int32_t addr; four bytes, little-endian order
864 1.11 fvdl * u_int32_t len; four bytes, little endian order
865 1.11 fvdl * };
866 1.11 fvdl */
867 1.11 fvdl mvi HADDR call dfdat_in_7;
868 1.11 fvdl }
869 1.11 fvdl
870 1.11 fvdl /* Track odd'ness */
871 1.11 fvdl test HCNT[0], 0x1 jz . + 2;
872 1.11 fvdl xor DATA_COUNT_ODD, 0x1;
873 1.11 fvdl
874 1.11 fvdl if ((ahc->features & AHC_ULTRA2) == 0) {
875 1.11 fvdl /* Load STCNT as well. It is a mirror of HCNT */
876 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
877 1.11 fvdl bmov STCNT, HCNT, 3;
878 1.11 fvdl } else {
879 1.11 fvdl call set_stcnt_from_hcnt;
880 1.11 fvdl }
881 1.11 fvdl }
882 1.11 fvdl
883 1.11 fvdl /* Advance the SG pointer */
884 1.11 fvdl clr A; /* add sizeof(struct scatter) */
885 1.11 fvdl add SG_NEXT[0],SG_SIZEOF;
886 1.11 fvdl adc SG_NEXT[1],A;
887 1.11 fvdl
888 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
889 1.11 fvdl test SSTAT0, TARGET jnz data_phase_loop;
890 1.11 fvdl }
891 1.11 fvdl test SSTAT1, REQINIT jz .;
892 1.11 fvdl test SSTAT1,PHASEMIS jz data_phase_loop;
893 1.11 fvdl
894 1.11 fvdl /* Ensure the last seg is visable at the shaddow layer */
895 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
896 1.11 fvdl mov DFCNTRL, DMAPARAMS;
897 1.11 fvdl test SSTAT0, SDONE jnz .;/* Wait for preload to complete */
898 1.11 fvdl }
899 1.2 mycroft
900 1.2 mycroft data_phase_finish:
901 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
902 1.11 fvdl call ultra2_dmafinish;
903 1.11 fvdl }
904 1.2 mycroft /*
905 1.2 mycroft * After a DMA finishes, save the SG and STCNT residuals back into the SCB
906 1.2 mycroft * We use STCNT instead of HCNT, since it's a reflection of how many bytes
907 1.2 mycroft * were transferred on the SCSI (as opposed to the host) bus.
908 1.2 mycroft */
909 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
910 1.11 fvdl bmov SCB_RESID_DCNT, STCNT, 3;
911 1.11 fvdl } else {
912 1.11 fvdl mov SCB_RESID_DCNT[0],STCNT[0];
913 1.11 fvdl mov SCB_RESID_DCNT[1],STCNT[1];
914 1.11 fvdl mov SCB_RESID_DCNT[2],STCNT[2];
915 1.11 fvdl }
916 1.11 fvdl mov SCB_RESID_SGCNT, SG_COUNT;
917 1.11 fvdl
918 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
919 1.11 fvdl or SXFRCTL0, CLRSTCNT|CLRCHN;
920 1.11 fvdl }
921 1.11 fvdl
922 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
923 1.11 fvdl test SEQ_FLAGS, DPHASE_PENDING jz ITloop;
924 1.11 fvdl and SEQ_FLAGS, ~DPHASE_PENDING;
925 1.11 fvdl /*
926 1.11 fvdl * For data-in phases, wait for any pending acks from the
927 1.11 fvdl * initiator before changing phase.
928 1.11 fvdl */
929 1.11 fvdl test DFCNTRL, DIRECTION jz target_ITloop;
930 1.11 fvdl test SSTAT1, REQINIT jnz .;
931 1.11 fvdl jmp target_ITloop;
932 1.11 fvdl }
933 1.11 fvdl jmp ITloop;
934 1.1 mycroft
935 1.4 explorer data_phase_overrun:
936 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
937 1.11 fvdl call ultra2_dmafinish;
938 1.11 fvdl or SXFRCTL0, CLRSTCNT|CLRCHN;
939 1.11 fvdl }
940 1.4 explorer /*
941 1.4 explorer * Turn off BITBUCKET mode and notify the host
942 1.4 explorer */
943 1.11 fvdl and SXFRCTL1, ~BITBUCKET;
944 1.11 fvdl mvi INTSTAT,DATA_OVERRUN;
945 1.11 fvdl jmp ITloop;
946 1.11 fvdl
947 1.11 fvdl ultra2_dmafinish:
948 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
949 1.11 fvdl test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
950 1.11 fvdl and DFCNTRL, ~SCSIEN;
951 1.11 fvdl test DFCNTRL, SCSIEN jnz .;
952 1.11 fvdl ultra2_dmafifoflush:
953 1.11 fvdl or DFCNTRL, FIFOFLUSH;
954 1.11 fvdl /*
955 1.11 fvdl * The FIFOEMP status bit on the Ultra2 class
956 1.11 fvdl * of controllers seems to be a bit flaky.
957 1.11 fvdl * It appears that if the FIFO is full and the
958 1.11 fvdl * transfer ends with some data in the REQ/ACK
959 1.11 fvdl * FIFO, FIFOEMP will fall temporarily
960 1.11 fvdl * as the data is transferred to the PCI bus.
961 1.11 fvdl * This glitch lasts for fewer than 5 clock cycles,
962 1.11 fvdl * so we work around the problem by ensuring the
963 1.11 fvdl * status bit stays false through a full glitch
964 1.11 fvdl * window.
965 1.11 fvdl */
966 1.11 fvdl test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
967 1.11 fvdl test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
968 1.11 fvdl test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
969 1.11 fvdl test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
970 1.11 fvdl test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
971 1.11 fvdl
972 1.11 fvdl ultra2_dmafifoempty:
973 1.11 fvdl /* Don't clobber an inprogress host data transfer */
974 1.11 fvdl test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty;
975 1.11 fvdl
976 1.11 fvdl ultra2_dmahalt:
977 1.11 fvdl and DFCNTRL, ~(SCSIEN|HDMAEN);
978 1.11 fvdl test DFCNTRL, HDMAEN jnz .;
979 1.11 fvdl ret;
980 1.11 fvdl }
981 1.4 explorer
982 1.11 fvdl if ((ahc->flags & AHC_INITIATORMODE) != 0) {
983 1.2 mycroft /*
984 1.2 mycroft * Command phase. Set up the DMA registers and let 'er rip.
985 1.2 mycroft */
986 1.1 mycroft p_command:
987 1.11 fvdl call assert;
988 1.1 mycroft
989 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
990 1.11 fvdl mov HCNT[0], SCB_CMDLEN;
991 1.11 fvdl bmov HCNT[1], ALLZEROS, 2;
992 1.11 fvdl if ((ahc->features & AHC_ULTRA2) == 0) {
993 1.11 fvdl bmov STCNT, HCNT, 3;
994 1.11 fvdl }
995 1.11 fvdl add NONE, -17, SCB_CMDLEN;
996 1.11 fvdl jc dma_cmd_data;
997 1.11 fvdl /*
998 1.11 fvdl * The data fifo seems to require 4 byte alligned
999 1.11 fvdl * transfers from the sequencer. Force this to
1000 1.11 fvdl * be the case by clearing HADDR[0] even though
1001 1.11 fvdl * we aren't going to touch host memeory.
1002 1.11 fvdl */
1003 1.11 fvdl bmov HADDR[0], ALLZEROS, 1;
1004 1.11 fvdl if ((ahc->features & AHC_ULTRA2) != 0) {
1005 1.11 fvdl mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
1006 1.11 fvdl } else {
1007 1.11 fvdl mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
1008 1.11 fvdl }
1009 1.11 fvdl bmov DFDAT, SCB_CMDSTORE, 16;
1010 1.11 fvdl jmp cmd_loop;
1011 1.11 fvdl dma_cmd_data:
1012 1.11 fvdl bmov HADDR, SCB_CMDPTR, 4;
1013 1.11 fvdl } else {
1014 1.11 fvdl mvi DINDEX, HADDR;
1015 1.11 fvdl mvi SCB_CMDPTR call bcopy_5;
1016 1.11 fvdl clr HCNT[1];
1017 1.11 fvdl clr HCNT[2];
1018 1.11 fvdl }
1019 1.11 fvdl
1020 1.11 fvdl if ((ahc->features & AHC_ULTRA2) == 0) {
1021 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) == 0) {
1022 1.11 fvdl call set_stcnt_from_hcnt;
1023 1.11 fvdl }
1024 1.11 fvdl mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
1025 1.11 fvdl } else {
1026 1.11 fvdl mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
1027 1.11 fvdl }
1028 1.11 fvdl cmd_loop:
1029 1.11 fvdl test SSTAT0, SDONE jnz . + 2;
1030 1.11 fvdl test SSTAT1, PHASEMIS jz cmd_loop;
1031 1.11 fvdl /*
1032 1.11 fvdl * Wait for our ACK to go-away on it's own
1033 1.11 fvdl * instead of being killed by SCSIEN getting cleared.
1034 1.11 fvdl */
1035 1.11 fvdl test SCSISIGI, ACKI jnz .;
1036 1.11 fvdl and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
1037 1.11 fvdl test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
1038 1.11 fvdl jmp ITloop;
1039 1.1 mycroft
1040 1.2 mycroft /*
1041 1.2 mycroft * Status phase. Wait for the data byte to appear, then read it
1042 1.2 mycroft * and store it into the SCB.
1043 1.2 mycroft */
1044 1.1 mycroft p_status:
1045 1.11 fvdl call assert;
1046 1.11 fvdl
1047 1.11 fvdl mov SCB_TARGET_STATUS, SCSIDATL;
1048 1.11 fvdl jmp ITloop;
1049 1.1 mycroft
1050 1.2 mycroft /*
1051 1.11 fvdl * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full
1052 1.11 fvdl * indentify message sequence and send it to the target. The host may
1053 1.11 fvdl * override this behavior by setting the MK_MESSAGE bit in the SCB
1054 1.11 fvdl * control byte. This will cause us to interrupt the host and allow
1055 1.11 fvdl * it to handle the message phase completely on its own. If the bit
1056 1.11 fvdl * associated with this target is set, we will also interrupt the host,
1057 1.11 fvdl * thereby allowing it to send a message on the next selection regardless
1058 1.11 fvdl * of the transaction being sent.
1059 1.11 fvdl *
1060 1.11 fvdl * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
1061 1.11 fvdl * This is done to allow the host to send messages outside of an identify
1062 1.11 fvdl * sequence while protecting the seqencer from testing the MK_MESSAGE bit
1063 1.11 fvdl * on an SCB that might not be for the current nexus. (For example, a
1064 1.12 wiz * BDR message in response to a bad reselection would leave us pointed to
1065 1.11 fvdl * an SCB that doesn't have anything to do with the current target).
1066 1.11 fvdl *
1067 1.11 fvdl * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
1068 1.11 fvdl * bus device reset).
1069 1.11 fvdl *
1070 1.11 fvdl * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
1071 1.11 fvdl * in case the target decides to put us in this phase for some strange
1072 1.11 fvdl * reason.
1073 1.2 mycroft */
1074 1.11 fvdl p_mesgout_retry:
1075 1.11 fvdl or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
1076 1.1 mycroft p_mesgout:
1077 1.11 fvdl mov SINDEX, MSG_OUT;
1078 1.11 fvdl cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
1079 1.11 fvdl test SCB_CONTROL,MK_MESSAGE jnz host_message_loop;
1080 1.11 fvdl mov FUNCTION1, SCB_TCL;
1081 1.11 fvdl mov A, FUNCTION1;
1082 1.11 fvdl if ((ahc->features & AHC_HS_MAILBOX) != 0) {
1083 1.11 fvdl /*
1084 1.11 fvdl * Work around a pausing bug in at least the aic7890.
1085 1.11 fvdl * If the host needs to update the TARGET_MSG_REQUEST
1086 1.11 fvdl * bit field, it will set the HS_MAILBOX to 1. In
1087 1.11 fvdl * response, we pause with a specific interrupt code
1088 1.11 fvdl * asking for the mask to be updated before we continue.
1089 1.11 fvdl * Ugh.
1090 1.11 fvdl */
1091 1.11 fvdl test HS_MAILBOX, 0xF0 jz . + 2;
1092 1.11 fvdl mvi INTSTAT, UPDATE_TMSG_REQ;
1093 1.11 fvdl nop;
1094 1.11 fvdl }
1095 1.11 fvdl mov SINDEX, TARGET_MSG_REQUEST[0];
1096 1.11 fvdl if ((ahc->features & AHC_TWIN) != 0) {
1097 1.11 fvdl /* Second Channel uses high byte bits */
1098 1.11 fvdl test SCB_TCL, SELBUSB jz . + 2;
1099 1.11 fvdl mov SINDEX, TARGET_MSG_REQUEST[1];
1100 1.11 fvdl } else if ((ahc->features & AHC_WIDE) != 0) {
1101 1.11 fvdl test SCB_TCL, 0x80 jz . + 2; /* target > 7 */
1102 1.11 fvdl mov SINDEX, TARGET_MSG_REQUEST[1];
1103 1.11 fvdl }
1104 1.11 fvdl test SINDEX, A jnz host_message_loop;
1105 1.11 fvdl p_mesgout_identify:
1106 1.11 fvdl and SINDEX,LID,SCB_TCL; /* lun */
1107 1.11 fvdl and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
1108 1.11 fvdl or SINDEX,A; /* or in disconnect privledge */
1109 1.11 fvdl or SINDEX,MSG_IDENTIFYFLAG;
1110 1.2 mycroft /*
1111 1.11 fvdl * Send a tag message if TAG_ENB is set in the SCB control block.
1112 1.11 fvdl * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
1113 1.2 mycroft */
1114 1.11 fvdl p_mesgout_tag:
1115 1.11 fvdl test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte;
1116 1.11 fvdl mov SCSIDATL, SINDEX; /* Send the identify message */
1117 1.11 fvdl call phase_lock;
1118 1.11 fvdl cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
1119 1.11 fvdl and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
1120 1.11 fvdl call phase_lock;
1121 1.11 fvdl cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
1122 1.11 fvdl mov SCB_TAG jmp p_mesgout_onebyte;
1123 1.11 fvdl /*
1124 1.11 fvdl * Interrupt the driver, and allow it to handle this message
1125 1.11 fvdl * phase and any required retries.
1126 1.11 fvdl */
1127 1.11 fvdl p_mesgout_from_host:
1128 1.11 fvdl cmp SINDEX, HOST_MSG jne p_mesgout_onebyte;
1129 1.11 fvdl jmp host_message_loop;
1130 1.11 fvdl
1131 1.11 fvdl p_mesgout_onebyte:
1132 1.11 fvdl mvi CLRSINT1, CLRATNO;
1133 1.11 fvdl mov SCSIDATL, SINDEX;
1134 1.2 mycroft
1135 1.2 mycroft /*
1136 1.11 fvdl * If the next bus phase after ATN drops is message out, it means
1137 1.2 mycroft * that the target is requesting that the last message(s) be resent.
1138 1.2 mycroft */
1139 1.11 fvdl call phase_lock;
1140 1.11 fvdl cmp LASTPHASE, P_MESGOUT je p_mesgout_retry;
1141 1.1 mycroft
1142 1.2 mycroft p_mesgout_done:
1143 1.11 fvdl mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
1144 1.11 fvdl mov LAST_MSG, MSG_OUT;
1145 1.11 fvdl mvi MSG_OUT, MSG_NOOP; /* No message left */
1146 1.11 fvdl jmp ITloop;
1147 1.1 mycroft
1148 1.2 mycroft /*
1149 1.2 mycroft * Message in phase. Bytes are read using Automatic PIO mode.
1150 1.2 mycroft */
1151 1.1 mycroft p_mesgin:
1152 1.11 fvdl mvi ACCUM call inb_first; /* read the 1st message byte */
1153 1.2 mycroft
1154 1.11 fvdl test A,MSG_IDENTIFYFLAG jnz mesgin_identify;
1155 1.11 fvdl cmp A,MSG_DISCONNECT je mesgin_disconnect;
1156 1.11 fvdl cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs;
1157 1.11 fvdl cmp ALLZEROS,A je mesgin_complete;
1158 1.11 fvdl cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs;
1159 1.11 fvdl cmp A,MSG_NOOP je mesgin_done;
1160 1.11 fvdl
1161 1.11 fvdl /*
1162 1.11 fvdl * Pushed message loop to allow the kernel to
1163 1.11 fvdl * run it's own message state engine. To avoid an
1164 1.11 fvdl * extra nop instruction after signaling the kernel,
1165 1.11 fvdl * we perform the phase_lock before checking to see
1166 1.11 fvdl * if we should exit the loop and skip the phase_lock
1167 1.11 fvdl * in the ITloop. Performing back to back phase_locks
1168 1.11 fvdl * shouldn't hurt, but why do it twice...
1169 1.11 fvdl */
1170 1.11 fvdl host_message_loop:
1171 1.11 fvdl mvi INTSTAT, HOST_MSG_LOOP;
1172 1.11 fvdl call phase_lock;
1173 1.11 fvdl cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1;
1174 1.11 fvdl jmp host_message_loop;
1175 1.2 mycroft
1176 1.2 mycroft mesgin_done:
1177 1.11 fvdl mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
1178 1.11 fvdl jmp ITloop;
1179 1.2 mycroft
1180 1.2 mycroft
1181 1.2 mycroft mesgin_complete:
1182 1.2 mycroft /*
1183 1.11 fvdl * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
1184 1.11 fvdl * and trigger a completion interrupt. Before doing so, check to see if there
1185 1.11 fvdl * is a residual or the status byte is something other than STATUS_GOOD (0).
1186 1.11 fvdl * In either of these conditions, we upload the SCB back to the host so it can
1187 1.11 fvdl * process this information. In the case of a non zero status byte, we
1188 1.11 fvdl * additionally interrupt the kernel driver synchronously, allowing it to
1189 1.11 fvdl * decide if sense should be retrieved. If the kernel driver wishes to request
1190 1.11 fvdl * sense, it will fill the kernel SCB with a request sense command and set
1191 1.11 fvdl * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload
1192 1.11 fvdl * the SCB, and process it as the next command by adding it to the waiting list.
1193 1.11 fvdl * If the kernel driver does not wish to request sense, it need only clear
1194 1.11 fvdl * RETURN_1, and the command is allowed to complete normally. We don't bother
1195 1.11 fvdl * to post to the QOUTFIFO in the error cases since it would require extra
1196 1.11 fvdl * work in the kernel driver to ensure that the entry was removed before the
1197 1.11 fvdl * command complete code tried processing it.
1198 1.2 mycroft */
1199 1.11 fvdl
1200 1.2 mycroft /*
1201 1.11 fvdl * First check for residuals
1202 1.2 mycroft */
1203 1.11 fvdl test SCB_RESID_SGCNT,0xff jnz upload_scb;
1204 1.11 fvdl test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */
1205 1.11 fvdl upload_scb:
1206 1.11 fvdl mvi DMAPARAMS, FIFORESET;
1207 1.11 fvdl mov SCB_TAG call dma_scb;
1208 1.11 fvdl check_status:
1209 1.11 fvdl test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */
1210 1.11 fvdl mvi INTSTAT,BAD_STATUS; /* let driver know */
1211 1.11 fvdl nop;
1212 1.11 fvdl cmp RETURN_1, SEND_SENSE jne complete;
1213 1.11 fvdl /* This SCB becomes the next to execute as it will retrieve sense */
1214 1.11 fvdl mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
1215 1.11 fvdl mov SCB_TAG call dma_scb;
1216 1.11 fvdl add_to_waiting_list:
1217 1.11 fvdl mov SCB_NEXT,WAITING_SCBH;
1218 1.11 fvdl mov WAITING_SCBH, SCBPTR;
1219 1.11 fvdl /*
1220 1.11 fvdl * Prepare our selection hardware before the busfree so we have a
1221 1.11 fvdl * high probability of winning arbitration.
1222 1.11 fvdl */
1223 1.11 fvdl call start_selection;
1224 1.11 fvdl jmp await_busfree;
1225 1.1 mycroft
1226 1.1 mycroft complete:
1227 1.11 fvdl /* If we are untagged, clear our address up in host ram */
1228 1.11 fvdl test SCB_CONTROL, TAG_ENB jnz complete_queue;
1229 1.11 fvdl mov A, SAVED_TCL;
1230 1.11 fvdl /* fvdl - let ahc_intr clear this to avoid race conditions */
1231 1.11 fvdl /* mvi UNTAGGEDSCB_OFFSET call post_byte_setup; */
1232 1.11 fvdl /* mvi SCB_LIST_NULL call post_byte; */
1233 1.11 fvdl
1234 1.11 fvdl complete_queue:
1235 1.11 fvdl mov SCB_TAG call complete_post;
1236 1.11 fvdl jmp await_busfree;
1237 1.11 fvdl }
1238 1.11 fvdl
1239 1.11 fvdl complete_post:
1240 1.11 fvdl /* Post the SCBID in SINDEX and issue an interrupt */
1241 1.11 fvdl call add_scb_to_free_list;
1242 1.11 fvdl mov ARG_1, SINDEX;
1243 1.11 fvdl if ((ahc->features & AHC_QUEUE_REGS) != 0) {
1244 1.11 fvdl mov A, SDSCB_QOFF;
1245 1.11 fvdl } else {
1246 1.11 fvdl mov A, QOUTPOS;
1247 1.11 fvdl }
1248 1.11 fvdl mvi QOUTFIFO_OFFSET call post_byte_setup;
1249 1.11 fvdl mov ARG_1 call post_byte;
1250 1.11 fvdl if ((ahc->features & AHC_QUEUE_REGS) == 0) {
1251 1.11 fvdl inc QOUTPOS;
1252 1.11 fvdl }
1253 1.11 fvdl mvi INTSTAT,CMDCMPLT ret;
1254 1.2 mycroft
1255 1.11 fvdl if ((ahc->flags & AHC_INITIATORMODE) != 0) {
1256 1.2 mycroft /*
1257 1.2 mycroft * Is it a disconnect message? Set a flag in the SCB to remind us
1258 1.2 mycroft * and await the bus going free.
1259 1.2 mycroft */
1260 1.2 mycroft mesgin_disconnect:
1261 1.11 fvdl or SCB_CONTROL,DISCONNECTED;
1262 1.11 fvdl call add_scb_to_disc_list;
1263 1.11 fvdl jmp await_busfree;
1264 1.2 mycroft
1265 1.2 mycroft /*
1266 1.11 fvdl * Save data pointers message:
1267 1.11 fvdl * Copying RAM values back to SCB, for Save Data Pointers message, but
1268 1.11 fvdl * only if we've actually been into a data phase to change them. This
1269 1.11 fvdl * protects against bogus data in scratch ram and the residual counts
1270 1.11 fvdl * since they are only initialized when we go into data_in or data_out.
1271 1.2 mycroft */
1272 1.2 mycroft mesgin_sdptrs:
1273 1.11 fvdl test SEQ_FLAGS, DPHASE jz mesgin_done;
1274 1.11 fvdl
1275 1.11 fvdl /*
1276 1.11 fvdl * The SCB SGPTR becomes the next one we'll download,
1277 1.11 fvdl * and the SCB DATAPTR becomes the current SHADDR.
1278 1.11 fvdl * Use the residual number since STCNT is corrupted by
1279 1.11 fvdl * any message transfer.
1280 1.11 fvdl */
1281 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
1282 1.11 fvdl bmov SCB_SGCOUNT, SG_COUNT, 5;
1283 1.11 fvdl bmov SCB_DATAPTR, SHADDR, 4;
1284 1.11 fvdl bmov SCB_DATACNT, SCB_RESID_DCNT, 3;
1285 1.11 fvdl } else {
1286 1.11 fvdl mvi DINDEX, SCB_SGCOUNT;
1287 1.11 fvdl mvi SG_COUNT call bcopy_5;
1288 1.11 fvdl
1289 1.11 fvdl mvi DINDEX, SCB_DATAPTR;
1290 1.11 fvdl mvi SHADDR call bcopy_4;
1291 1.11 fvdl mvi SCB_RESID_DCNT call bcopy_3;
1292 1.11 fvdl }
1293 1.11 fvdl jmp mesgin_done;
1294 1.1 mycroft
1295 1.2 mycroft /*
1296 1.2 mycroft * Restore pointers message? Data pointers are recopied from the
1297 1.2 mycroft * SCB anytime we enter a data phase for the first time, so all
1298 1.2 mycroft * we need to do is clear the DPHASE flag and let the data phase
1299 1.2 mycroft * code do the rest.
1300 1.2 mycroft */
1301 1.2 mycroft mesgin_rdptrs:
1302 1.11 fvdl and SEQ_FLAGS, ~DPHASE; /*
1303 1.11 fvdl * We'll reload them
1304 1.2 mycroft * the next time through
1305 1.11 fvdl * the dataphase.
1306 1.2 mycroft */
1307 1.11 fvdl jmp mesgin_done;
1308 1.2 mycroft
1309 1.2 mycroft /*
1310 1.2 mycroft * Identify message? For a reconnecting target, this tells us the lun
1311 1.2 mycroft * that the reconnection is for - find the correct SCB and switch to it,
1312 1.2 mycroft * clearing the "disconnected" bit so we don't "find" it by accident later.
1313 1.2 mycroft */
1314 1.2 mycroft mesgin_identify:
1315 1.11 fvdl if ((ahc->features & AHC_WIDE) != 0) {
1316 1.11 fvdl and A,0x0f; /* lun in lower four bits */
1317 1.11 fvdl } else {
1318 1.11 fvdl and A,0x07; /* lun in lower three bits */
1319 1.11 fvdl }
1320 1.11 fvdl or SAVED_TCL,A; /* SAVED_TCL should be complete now */
1321 1.11 fvdl
1322 1.11 fvdl mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */
1323 1.11 fvdl call get_untagged_SCBID;
1324 1.11 fvdl cmp ARG_1, SCB_LIST_NULL je snoop_tag;
1325 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) != 0) {
1326 1.11 fvdl test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
1327 1.11 fvdl }
1328 1.11 fvdl /*
1329 1.11 fvdl * If the SCB was found in the disconnected list (as is
1330 1.11 fvdl * always the case in non-paging scenarios), SCBPTR is already
1331 1.11 fvdl * set to the correct SCB. So, simply setup the SCB and get
1332 1.11 fvdl * on with things.
1333 1.11 fvdl */
1334 1.11 fvdl call rem_scb_from_disc_list;
1335 1.11 fvdl jmp setup_SCB;
1336 1.2 mycroft /*
1337 1.2 mycroft * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
1338 1.11 fvdl * If we get one, we use the tag returned to find the proper
1339 1.11 fvdl * SCB. With SCB paging, this requires using search for both tagged
1340 1.2 mycroft * and non-tagged transactions since the SCB may exist in any slot.
1341 1.2 mycroft * If we're not using SCB paging, we can use the tag as the direct
1342 1.2 mycroft * index to the SCB.
1343 1.2 mycroft */
1344 1.11 fvdl snoop_tag:
1345 1.11 fvdl mov NONE,SCSIDATL; /* ACK Identify MSG */
1346 1.2 mycroft snoop_tag_loop:
1347 1.11 fvdl call phase_lock;
1348 1.11 fvdl cmp LASTPHASE, P_MESGIN jne not_found;
1349 1.11 fvdl cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
1350 1.2 mycroft get_tag:
1351 1.11 fvdl mvi ARG_1 call inb_next; /* tag value */
1352 1.2 mycroft
1353 1.11 fvdl /*
1354 1.11 fvdl * Ensure that the SCB the tag points to is for
1355 1.11 fvdl * an SCB transaction to the reconnecting target.
1356 1.11 fvdl */
1357 1.11 fvdl use_retrieveSCB:
1358 1.11 fvdl call retrieveSCB;
1359 1.1 mycroft setup_SCB:
1360 1.11 fvdl mov A, SAVED_TCL;
1361 1.11 fvdl cmp SCB_TCL, A jne not_found_cleanup_scb;
1362 1.11 fvdl test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
1363 1.11 fvdl and SCB_CONTROL,~DISCONNECTED;
1364 1.11 fvdl or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
1365 1.11 fvdl call set_transfer_settings;
1366 1.11 fvdl /* See if the host wants to send a message upon reconnection */
1367 1.11 fvdl test SCB_CONTROL, MK_MESSAGE jz mesgin_done;
1368 1.11 fvdl and SCB_CONTROL, ~MK_MESSAGE;
1369 1.11 fvdl mvi HOST_MSG call mk_mesg;
1370 1.11 fvdl jmp mesgin_done;
1371 1.11 fvdl
1372 1.11 fvdl not_found_cleanup_scb:
1373 1.11 fvdl test SCB_CONTROL, DISCONNECTED jz . + 3;
1374 1.11 fvdl call add_scb_to_disc_list;
1375 1.11 fvdl jmp not_found;
1376 1.11 fvdl call add_scb_to_free_list;
1377 1.11 fvdl not_found:
1378 1.11 fvdl mvi INTSTAT, NO_MATCH;
1379 1.11 fvdl jmp mesgin_done;
1380 1.2 mycroft
1381 1.2 mycroft /*
1382 1.2 mycroft * [ ADD MORE MESSAGE HANDLING HERE ]
1383 1.2 mycroft */
1384 1.2 mycroft
1385 1.2 mycroft /*
1386 1.2 mycroft * Locking the driver out, build a one-byte message passed in SINDEX
1387 1.2 mycroft * if there is no active message already. SINDEX is returned intact.
1388 1.2 mycroft */
1389 1.2 mycroft mk_mesg:
1390 1.11 fvdl or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
1391 1.11 fvdl mov MSG_OUT,SINDEX ret;
1392 1.2 mycroft
1393 1.2 mycroft /*
1394 1.2 mycroft * Functions to read data in Automatic PIO mode.
1395 1.2 mycroft *
1396 1.2 mycroft * According to Adaptec's documentation, an ACK is not sent on input from
1397 1.2 mycroft * the target until SCSIDATL is read from. So we wait until SCSIDATL is
1398 1.2 mycroft * latched (the usual way), then read the data byte directly off the bus
1399 1.2 mycroft * using SCSIBUSL. When we have pulled the ATN line, or we just want to
1400 1.2 mycroft * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI
1401 1.2 mycroft * spec guarantees that the target will hold the data byte on the bus until
1402 1.2 mycroft * we send our ACK.
1403 1.2 mycroft *
1404 1.2 mycroft * The assumption here is that these are called in a particular sequence,
1405 1.2 mycroft * and that REQ is already set when inb_first is called. inb_{first,next}
1406 1.2 mycroft * use the same calling convention as inb.
1407 1.2 mycroft */
1408 1.11 fvdl inb_next_wait_perr:
1409 1.11 fvdl mvi INTSTAT, PERR_DETECTED;
1410 1.11 fvdl jmp inb_next_wait;
1411 1.2 mycroft inb_next:
1412 1.11 fvdl mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
1413 1.2 mycroft inb_next_wait:
1414 1.11 fvdl /*
1415 1.11 fvdl * If there is a parity error, wait for the kernel to
1416 1.11 fvdl * see the interrupt and prepare our message response
1417 1.11 fvdl * before continuing.
1418 1.11 fvdl */
1419 1.11 fvdl test SSTAT1, REQINIT jz inb_next_wait;
1420 1.11 fvdl test SSTAT1, SCSIPERR jnz inb_next_wait_perr;
1421 1.11 fvdl inb_next_check_phase:
1422 1.11 fvdl and LASTPHASE, PHASE_MASK, SCSISIGI;
1423 1.11 fvdl cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
1424 1.1 mycroft inb_first:
1425 1.11 fvdl mov DINDEX,SINDEX;
1426 1.11 fvdl mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/
1427 1.2 mycroft inb_last:
1428 1.11 fvdl mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
1429 1.11 fvdl }
1430 1.1 mycroft
1431 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
1432 1.11 fvdl /*
1433 1.11 fvdl * Change to a new phase. If we are changing the state of the I/O signal,
1434 1.11 fvdl * from out to in, wait an additional data release delay before continuing.
1435 1.11 fvdl */
1436 1.11 fvdl change_phase:
1437 1.11 fvdl /* Wait for preceeding I/O session to complete. */
1438 1.11 fvdl test SCSISIGI, ACKI jnz .;
1439 1.11 fvdl
1440 1.11 fvdl /* Change the phase */
1441 1.11 fvdl and DINDEX, IOI, SCSISIGI;
1442 1.11 fvdl mov SCSISIGO, SINDEX;
1443 1.11 fvdl and A, IOI, SINDEX;
1444 1.11 fvdl
1445 1.11 fvdl /*
1446 1.11 fvdl * If the data direction has changed, from
1447 1.11 fvdl * out (initiator driving) to in (target driving),
1448 1.11 fvdl * we must waitat least a data release delay plus
1449 1.11 fvdl * the normal bus settle delay. [SCSI III SPI 10.11.0]
1450 1.11 fvdl */
1451 1.11 fvdl cmp DINDEX, A je change_phase_wait;
1452 1.11 fvdl test SINDEX, IOI jz change_phase_wait;
1453 1.11 fvdl call change_phase_wait;
1454 1.11 fvdl change_phase_wait:
1455 1.11 fvdl nop;
1456 1.11 fvdl nop;
1457 1.11 fvdl nop;
1458 1.11 fvdl nop ret;
1459 1.11 fvdl
1460 1.11 fvdl /*
1461 1.11 fvdl * Send a byte to an initiator in Automatic PIO mode.
1462 1.11 fvdl */
1463 1.11 fvdl target_outb:
1464 1.11 fvdl or SXFRCTL0, SPIOEN;
1465 1.11 fvdl test SSTAT0, SPIORDY jz .;
1466 1.11 fvdl mov SCSIDATL, SINDEX;
1467 1.11 fvdl test SSTAT0, SPIORDY jz .;
1468 1.11 fvdl and SXFRCTL0, ~SPIOEN ret;
1469 1.11 fvdl }
1470 1.11 fvdl
1471 1.2 mycroft mesgin_phasemis:
1472 1.2 mycroft /*
1473 1.2 mycroft * We expected to receive another byte, but the target changed phase
1474 1.2 mycroft */
1475 1.11 fvdl mvi INTSTAT, MSGIN_PHASEMIS;
1476 1.11 fvdl jmp ITloop;
1477 1.1 mycroft
1478 1.2 mycroft /*
1479 1.2 mycroft * DMA data transfer. HADDR and HCNT must be loaded first, and
1480 1.2 mycroft * SINDEX should contain the value to load DFCNTRL with - 0x3d for
1481 1.2 mycroft * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
1482 1.2 mycroft * during initialization.
1483 1.2 mycroft */
1484 1.1 mycroft dma:
1485 1.11 fvdl mov DFCNTRL,SINDEX;
1486 1.11 fvdl dma_loop:
1487 1.11 fvdl test SSTAT0,DMADONE jnz dma_dmadone;
1488 1.11 fvdl test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */
1489 1.11 fvdl dma_phasemis:
1490 1.2 mycroft
1491 1.2 mycroft /*
1492 1.2 mycroft * We will be "done" DMAing when the transfer count goes to zero, or
1493 1.2 mycroft * the target changes the phase (in light of this, it makes sense that
1494 1.2 mycroft * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are
1495 1.2 mycroft * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
1496 1.2 mycroft * magically on STCNT=0 or a phase change, so just wait for FIFO empty
1497 1.2 mycroft * status.
1498 1.2 mycroft */
1499 1.11 fvdl dma_checkfifo:
1500 1.11 fvdl test DFCNTRL,DIRECTION jnz dma_fifoempty;
1501 1.11 fvdl dma_fifoflush:
1502 1.11 fvdl test DFSTATUS,FIFOEMP jz dma_fifoflush;
1503 1.11 fvdl
1504 1.11 fvdl dma_fifoempty:
1505 1.11 fvdl /* Don't clobber an inprogress host data transfer */
1506 1.11 fvdl test DFSTATUS, MREQPEND jnz dma_fifoempty;
1507 1.2 mycroft /*
1508 1.10 mjacob * Now shut the DMA enables off and make sure that the DMA enables are
1509 1.2 mycroft * actually off first lest we get an ILLSADDR.
1510 1.2 mycroft */
1511 1.11 fvdl dma_dmadone:
1512 1.11 fvdl and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
1513 1.11 fvdl dma_halt:
1514 1.11 fvdl /*
1515 1.11 fvdl * Some revisions of the aic7880 have a problem where, if the
1516 1.11 fvdl * data fifo is full, but the PCI input latch is not empty,
1517 1.11 fvdl * HDMAEN cannot be cleared. The fix used here is to attempt
1518 1.11 fvdl * to drain the data fifo until there is space for the input
1519 1.11 fvdl * latch to drain and HDMAEN de-asserts.
1520 1.11 fvdl */
1521 1.11 fvdl if ((ahc->features & AHC_ULTRA2) == 0) {
1522 1.11 fvdl mov NONE, DFDAT;
1523 1.11 fvdl }
1524 1.11 fvdl test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
1525 1.6 gibbs return:
1526 1.11 fvdl ret;
1527 1.1 mycroft
1528 1.2 mycroft /*
1529 1.2 mycroft * Assert that if we've been reselected, then we've seen an IDENTIFY
1530 1.2 mycroft * message.
1531 1.2 mycroft */
1532 1.1 mycroft assert:
1533 1.11 fvdl test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */
1534 1.1 mycroft
1535 1.11 fvdl mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */
1536 1.1 mycroft
1537 1.2 mycroft /*
1538 1.11 fvdl * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
1539 1.11 fvdl * or by the SCBID ARG_1. The search begins at the SCB index passed in
1540 1.11 fvdl * via SINDEX which is an SCB that must be on the disconnected list. If
1541 1.11 fvdl * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
1542 1.11 fvdl * is set to the proper SCB.
1543 1.2 mycroft */
1544 1.1 mycroft findSCB:
1545 1.11 fvdl mov SCBPTR,SINDEX; /* Initialize SCBPTR */
1546 1.11 fvdl cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID;
1547 1.11 fvdl mov A, SAVED_TCL;
1548 1.11 fvdl mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */
1549 1.11 fvdl findSCB_by_SCBID:
1550 1.11 fvdl mov A, ARG_1; /* Tag passed in ARG_1 */
1551 1.11 fvdl mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */
1552 1.11 fvdl findSCB_next:
1553 1.11 fvdl mov ARG_2, SCBPTR;
1554 1.11 fvdl cmp SCB_NEXT, SCB_LIST_NULL je notFound;
1555 1.11 fvdl mov SCBPTR,SCB_NEXT;
1556 1.11 fvdl dec SINDEX; /* Last comparison moved us too far */
1557 1.11 fvdl findSCB_loop:
1558 1.11 fvdl cmp SINDIR, A jne findSCB_next;
1559 1.11 fvdl mov SINDEX, SCBPTR ret;
1560 1.11 fvdl notFound:
1561 1.11 fvdl mvi SINDEX, SCB_LIST_NULL ret;
1562 1.11 fvdl
1563 1.11 fvdl /*
1564 1.11 fvdl * Retrieve an SCB by SCBID first searching the disconnected list falling
1565 1.11 fvdl * back to DMA'ing the SCB down from the host. This routine assumes that
1566 1.11 fvdl * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
1567 1.11 fvdl * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL,
1568 1.11 fvdl * we go directly to the host for the SCB.
1569 1.11 fvdl */
1570 1.11 fvdl retrieveSCB:
1571 1.11 fvdl test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host;
1572 1.11 fvdl mov SCBPTR call findSCB; /* Continue the search */
1573 1.11 fvdl cmp SINDEX, SCB_LIST_NULL je retrieve_from_host;
1574 1.11 fvdl
1575 1.11 fvdl /*
1576 1.11 fvdl * This routine expects SINDEX to contain the index of the SCB to be
1577 1.11 fvdl * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
1578 1.11 fvdl * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
1579 1.11 fvdl * if it is at the head.
1580 1.11 fvdl */
1581 1.11 fvdl rem_scb_from_disc_list:
1582 1.2 mycroft /* Remove this SCB from the disconnection list */
1583 1.11 fvdl cmp ARG_2, SCB_LIST_NULL je rHead;
1584 1.11 fvdl mov DINDEX, SCB_NEXT;
1585 1.11 fvdl mov SCBPTR, ARG_2;
1586 1.11 fvdl mov SCB_NEXT, DINDEX;
1587 1.11 fvdl mov SCBPTR, SINDEX ret;
1588 1.2 mycroft rHead:
1589 1.11 fvdl mov DISCONNECTED_SCBH,SCB_NEXT ret;
1590 1.2 mycroft
1591 1.11 fvdl retrieve_from_host:
1592 1.2 mycroft /*
1593 1.11 fvdl * We didn't find it. Pull an SCB and DMA down the one we want.
1594 1.11 fvdl * We should never get here in the non-paging case.
1595 1.2 mycroft */
1596 1.11 fvdl mov ALLZEROS call get_free_or_disc_scb;
1597 1.11 fvdl mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
1598 1.11 fvdl /* Jump instead of call as we want to return anyway */
1599 1.11 fvdl mov ARG_1 jmp dma_scb;
1600 1.11 fvdl
1601 1.11 fvdl /*
1602 1.11 fvdl * Determine whether a target is using tagged or non-tagged transactions
1603 1.11 fvdl * by first looking for a matching transaction based on the TCL and if
1604 1.11 fvdl * that fails, looking up this device in the host's untagged SCB array.
1605 1.11 fvdl * The TCL to search for is assumed to be in SAVED_TCL. The value is
1606 1.11 fvdl * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
1607 1.11 fvdl * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
1608 1.11 fvdl * in an SCB instead of having to go to the host.
1609 1.11 fvdl */
1610 1.11 fvdl get_untagged_SCBID:
1611 1.11 fvdl cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
1612 1.11 fvdl mvi ARG_1, SCB_LIST_NULL;
1613 1.11 fvdl mov DISCONNECTED_SCBH call findSCB;
1614 1.11 fvdl cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host;
1615 1.11 fvdl or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
1616 1.11 fvdl test SCB_CONTROL, TAG_ENB jnz . + 2;
1617 1.11 fvdl mov ARG_1, SCB_TAG ret;
1618 1.11 fvdl mvi ARG_1, SCB_LIST_NULL ret;
1619 1.11 fvdl
1620 1.11 fvdl /*
1621 1.11 fvdl * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
1622 1.11 fvdl * and a base address of SCBID_ADDR. The byte is returned in RETURN_2.
1623 1.11 fvdl */
1624 1.11 fvdl fetch_byte:
1625 1.11 fvdl mov ARG_2, SINDEX;
1626 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
1627 1.11 fvdl mvi DINDEX, CCHADDR;
1628 1.11 fvdl mvi SCBID_ADDR call set_1byte_addr;
1629 1.11 fvdl mvi CCHCNT, 1;
1630 1.11 fvdl mvi CCSGCTL, CCSGEN|CCSGRESET;
1631 1.11 fvdl test CCSGCTL, CCSGDONE jz .;
1632 1.11 fvdl mvi CCSGCTL, CCSGRESET;
1633 1.11 fvdl bmov RETURN_2, CCSGRAM, 1 ret;
1634 1.11 fvdl } else {
1635 1.11 fvdl mvi DINDEX, HADDR;
1636 1.11 fvdl mvi SCBID_ADDR call set_1byte_addr;
1637 1.11 fvdl mvi HCNT[0], 1;
1638 1.11 fvdl clr HCNT[1];
1639 1.11 fvdl clr HCNT[2];
1640 1.11 fvdl mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
1641 1.11 fvdl call dma_finish;
1642 1.11 fvdl mov RETURN_2, DFDAT ret;
1643 1.11 fvdl }
1644 1.11 fvdl
1645 1.11 fvdl /*
1646 1.11 fvdl * Prepare the hardware to post a byte to host memory given an
1647 1.11 fvdl * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
1648 1.11 fvdl */
1649 1.11 fvdl post_byte_setup:
1650 1.11 fvdl mov ARG_2, SINDEX;
1651 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
1652 1.11 fvdl mvi DINDEX, CCHADDR;
1653 1.11 fvdl mvi SCBID_ADDR call set_1byte_addr;
1654 1.11 fvdl mvi CCHCNT, 1;
1655 1.11 fvdl mvi CCSCBCTL, CCSCBRESET ret;
1656 1.11 fvdl } else {
1657 1.11 fvdl mvi DINDEX, HADDR;
1658 1.11 fvdl mvi SCBID_ADDR call set_1byte_addr;
1659 1.11 fvdl mvi HCNT[0], 1;
1660 1.11 fvdl clr HCNT[1];
1661 1.11 fvdl clr HCNT[2];
1662 1.11 fvdl mvi DFCNTRL, FIFORESET ret;
1663 1.11 fvdl }
1664 1.11 fvdl
1665 1.11 fvdl post_byte:
1666 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
1667 1.11 fvdl bmov CCSCBRAM, SINDEX, 1;
1668 1.11 fvdl or CCSCBCTL, CCSCBEN|CCSCBRESET;
1669 1.11 fvdl test CCSCBCTL, CCSCBDONE jz .;
1670 1.11 fvdl clr CCSCBCTL ret;
1671 1.11 fvdl } else {
1672 1.11 fvdl mov DFDAT, SINDEX;
1673 1.11 fvdl or DFCNTRL, HDMAEN|FIFOFLUSH;
1674 1.11 fvdl jmp dma_finish;
1675 1.11 fvdl }
1676 1.11 fvdl
1677 1.11 fvdl get_SCBID_from_host:
1678 1.11 fvdl mov A, SAVED_TCL;
1679 1.11 fvdl mvi UNTAGGEDSCB_OFFSET call fetch_byte;
1680 1.11 fvdl mov RETURN_1, RETURN_2 ret;
1681 1.11 fvdl
1682 1.11 fvdl phase_lock_perr:
1683 1.11 fvdl mvi INTSTAT, PERR_DETECTED;
1684 1.11 fvdl phase_lock:
1685 1.11 fvdl /*
1686 1.11 fvdl * If there is a parity error, wait for the kernel to
1687 1.11 fvdl * see the interrupt and prepare our message response
1688 1.11 fvdl * before continuing.
1689 1.11 fvdl */
1690 1.11 fvdl test SSTAT1, REQINIT jz phase_lock;
1691 1.11 fvdl test SSTAT1, SCSIPERR jnz phase_lock_perr;
1692 1.11 fvdl phase_lock_latch_phase:
1693 1.11 fvdl and SCSISIGO, PHASE_MASK, SCSISIGI;
1694 1.11 fvdl and LASTPHASE, PHASE_MASK, SCSISIGI ret;
1695 1.11 fvdl
1696 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) == 0) {
1697 1.11 fvdl set_stcnt_from_hcnt:
1698 1.11 fvdl mov STCNT[0], HCNT[0];
1699 1.11 fvdl mov STCNT[1], HCNT[1];
1700 1.11 fvdl mov STCNT[2], HCNT[2] ret;
1701 1.11 fvdl
1702 1.11 fvdl bcopy_7:
1703 1.11 fvdl mov DINDIR, SINDIR;
1704 1.11 fvdl mov DINDIR, SINDIR;
1705 1.11 fvdl bcopy_5:
1706 1.11 fvdl mov DINDIR, SINDIR;
1707 1.11 fvdl bcopy_4:
1708 1.11 fvdl mov DINDIR, SINDIR;
1709 1.11 fvdl bcopy_3:
1710 1.11 fvdl mov DINDIR, SINDIR;
1711 1.11 fvdl mov DINDIR, SINDIR;
1712 1.11 fvdl mov DINDIR, SINDIR ret;
1713 1.11 fvdl }
1714 1.11 fvdl
1715 1.11 fvdl if ((ahc->flags & AHC_TARGETMODE) != 0) {
1716 1.11 fvdl /*
1717 1.11 fvdl * Setup addr assuming that A is an index into
1718 1.11 fvdl * an array of 32byte objects, SINDEX contains
1719 1.11 fvdl * the base address of that array, and DINDEX
1720 1.11 fvdl * contains the base address of the location
1721 1.11 fvdl * to store the indexed address.
1722 1.11 fvdl */
1723 1.11 fvdl set_32byte_addr:
1724 1.11 fvdl shr ARG_2, 3, A;
1725 1.11 fvdl shl A, 5;
1726 1.11 fvdl jmp set_1byte_addr;
1727 1.11 fvdl }
1728 1.11 fvdl
1729 1.11 fvdl /*
1730 1.11 fvdl * Setup addr assuming that A is an index into
1731 1.11 fvdl * an array of 64byte objects, SINDEX contains
1732 1.11 fvdl * the base address of that array, and DINDEX
1733 1.11 fvdl * contains the base address of the location
1734 1.11 fvdl * to store the indexed address.
1735 1.11 fvdl */
1736 1.11 fvdl set_64byte_addr:
1737 1.11 fvdl shr ARG_2, 2, A;
1738 1.11 fvdl shl A, 6;
1739 1.11 fvdl
1740 1.11 fvdl /*
1741 1.11 fvdl * Setup addr assuming that A + (ARG_1 * 256) is an
1742 1.11 fvdl * index into an array of 1byte objects, SINDEX contains
1743 1.11 fvdl * the base address of that array, and DINDEX contains
1744 1.11 fvdl * the base address of the location to store the computed
1745 1.11 fvdl * address.
1746 1.11 fvdl */
1747 1.11 fvdl set_1byte_addr:
1748 1.11 fvdl add DINDIR, A, SINDIR;
1749 1.11 fvdl mov A, ARG_2;
1750 1.11 fvdl adc DINDIR, A, SINDIR;
1751 1.11 fvdl clr A;
1752 1.11 fvdl adc DINDIR, A, SINDIR;
1753 1.11 fvdl adc DINDIR, A, SINDIR ret;
1754 1.11 fvdl
1755 1.11 fvdl /*
1756 1.11 fvdl * Either post or fetch and SCB from host memory based on the
1757 1.11 fvdl * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
1758 1.11 fvdl */
1759 1.11 fvdl dma_scb:
1760 1.11 fvdl mov A, SINDEX;
1761 1.11 fvdl if ((ahc->features & AHC_CMD_CHAN) != 0) {
1762 1.11 fvdl mvi DINDEX, CCHADDR;
1763 1.11 fvdl mvi HSCB_ADDR call set_64byte_addr;
1764 1.11 fvdl mov CCSCBPTR, SCBPTR;
1765 1.11 fvdl test DMAPARAMS, DIRECTION jz dma_scb_tohost;
1766 1.11 fvdl mvi CCHCNT, SCB_64BYTE_SIZE;
1767 1.11 fvdl mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
1768 1.11 fvdl cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
1769 1.11 fvdl jmp dma_scb_finish;
1770 1.11 fvdl dma_scb_tohost:
1771 1.11 fvdl mvi CCHCNT, SCB_32BYTE_SIZE;
1772 1.11 fvdl if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
1773 1.11 fvdl mvi CCSCBCTL, CCSCBRESET;
1774 1.11 fvdl bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE;
1775 1.11 fvdl or CCSCBCTL, CCSCBEN|CCSCBRESET;
1776 1.11 fvdl test CCSCBCTL, CCSCBDONE jz .;
1777 1.11 fvdl } else {
1778 1.11 fvdl mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
1779 1.11 fvdl cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
1780 1.11 fvdl }
1781 1.11 fvdl dma_scb_finish:
1782 1.11 fvdl clr CCSCBCTL;
1783 1.11 fvdl test CCSCBCTL, CCARREN|CCSCBEN jnz .;
1784 1.11 fvdl ret;
1785 1.11 fvdl } else {
1786 1.11 fvdl mvi DINDEX, HADDR;
1787 1.11 fvdl mvi HSCB_ADDR call set_64byte_addr;
1788 1.11 fvdl mvi HCNT[0], SCB_32BYTE_SIZE;
1789 1.11 fvdl clr HCNT[1];
1790 1.11 fvdl clr HCNT[2];
1791 1.11 fvdl mov DFCNTRL, DMAPARAMS;
1792 1.11 fvdl test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
1793 1.11 fvdl /* Fill it with the SCB data */
1794 1.11 fvdl copy_scb_tofifo:
1795 1.11 fvdl mvi SINDEX, SCB_CONTROL;
1796 1.11 fvdl add A, SCB_32BYTE_SIZE, SINDEX;
1797 1.11 fvdl copy_scb_tofifo_loop:
1798 1.11 fvdl mov DFDAT,SINDIR;
1799 1.11 fvdl mov DFDAT,SINDIR;
1800 1.11 fvdl mov DFDAT,SINDIR;
1801 1.11 fvdl mov DFDAT,SINDIR;
1802 1.11 fvdl mov DFDAT,SINDIR;
1803 1.11 fvdl mov DFDAT,SINDIR;
1804 1.11 fvdl mov DFDAT,SINDIR;
1805 1.11 fvdl cmp SINDEX, A jne copy_scb_tofifo_loop;
1806 1.11 fvdl or DFCNTRL, HDMAEN|FIFOFLUSH;
1807 1.11 fvdl dma_scb_fromhost:
1808 1.11 fvdl call dma_finish;
1809 1.11 fvdl /* If we were putting the SCB, we are done */
1810 1.11 fvdl test DMAPARAMS, DIRECTION jz return;
1811 1.11 fvdl mvi SCB_CONTROL call dfdat_in_7;
1812 1.11 fvdl call dfdat_in_7_continued;
1813 1.11 fvdl call dfdat_in_7_continued;
1814 1.11 fvdl jmp dfdat_in_7_continued;
1815 1.11 fvdl dfdat_in_7:
1816 1.11 fvdl mov DINDEX,SINDEX;
1817 1.11 fvdl dfdat_in_7_continued:
1818 1.11 fvdl mov DINDIR,DFDAT;
1819 1.11 fvdl mov DINDIR,DFDAT;
1820 1.11 fvdl mov DINDIR,DFDAT;
1821 1.11 fvdl mov DINDIR,DFDAT;
1822 1.11 fvdl mov DINDIR,DFDAT;
1823 1.11 fvdl mov DINDIR,DFDAT;
1824 1.11 fvdl mov DINDIR,DFDAT ret;
1825 1.11 fvdl }
1826 1.11 fvdl
1827 1.2 mycroft
1828 1.2 mycroft /*
1829 1.11 fvdl * Wait for DMA from host memory to data FIFO to complete, then disable
1830 1.11 fvdl * DMA and wait for it to acknowledge that it's off.
1831 1.2 mycroft */
1832 1.11 fvdl dma_finish:
1833 1.11 fvdl test DFSTATUS,HDONE jz dma_finish;
1834 1.11 fvdl /* Turn off DMA */
1835 1.11 fvdl and DFCNTRL, ~HDMAEN;
1836 1.11 fvdl test DFCNTRL, HDMAEN jnz .;
1837 1.11 fvdl ret;
1838 1.11 fvdl
1839 1.11 fvdl add_scb_to_free_list:
1840 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) != 0) {
1841 1.11 fvdl mov SCB_NEXT, FREE_SCBH;
1842 1.11 fvdl mvi SCB_TAG, SCB_LIST_NULL;
1843 1.11 fvdl mov FREE_SCBH, SCBPTR ret;
1844 1.11 fvdl } else {
1845 1.11 fvdl mvi SCB_TAG, SCB_LIST_NULL ret;
1846 1.11 fvdl }
1847 1.11 fvdl
1848 1.11 fvdl if ((ahc->flags & AHC_PAGESCBS) != 0) {
1849 1.11 fvdl get_free_or_disc_scb:
1850 1.11 fvdl cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
1851 1.11 fvdl cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
1852 1.11 fvdl return_error:
1853 1.11 fvdl mvi SINDEX, SCB_LIST_NULL ret;
1854 1.11 fvdl dequeue_disc_scb:
1855 1.11 fvdl mov SCBPTR, DISCONNECTED_SCBH;
1856 1.11 fvdl dma_up_scb:
1857 1.11 fvdl mvi DMAPARAMS, FIFORESET;
1858 1.11 fvdl mov SCB_TAG call dma_scb;
1859 1.11 fvdl unlink_disc_scb:
1860 1.11 fvdl mov DISCONNECTED_SCBH, SCB_NEXT ret;
1861 1.11 fvdl dequeue_free_scb:
1862 1.11 fvdl mov SCBPTR, FREE_SCBH;
1863 1.11 fvdl mov FREE_SCBH, SCB_NEXT ret;
1864 1.11 fvdl }
1865 1.2 mycroft
1866 1.11 fvdl add_scb_to_disc_list:
1867 1.2 mycroft /*
1868 1.11 fvdl * Link this SCB into the DISCONNECTED list. This list holds the
1869 1.11 fvdl * candidates for paging out an SCB if one is needed for a new command.
1870 1.11 fvdl * Modifying the disconnected list is a critical(pause dissabled) section.
1871 1.2 mycroft */
1872 1.11 fvdl mov SCB_NEXT, DISCONNECTED_SCBH;
1873 1.11 fvdl mov DISCONNECTED_SCBH, SCBPTR ret;
1874