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