Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. |
| 3 | * |
| 4 | * Copyright (c) 1994-1999 Justin Gibbs. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions, and the following disclaimer, |
| 12 | * without modification, immediately at the beginning of the file. |
| 13 | * 2. The name of the author may not be used to endorse or promote products |
| 14 | * derived from this software without specific prior written permission. |
| 15 | * |
| 16 | * Where this Software is combined with software released under the terms of |
| 17 | * the GNU General Public License (GPL) and the terms of the GPL would require the |
| 18 | * combined work to also be released under the terms of the GPL, the terms |
| 19 | * and conditions of this License will apply in addition to those of the |
| 20 | * GPL with the exception of any terms or conditions of this License that |
| 21 | * conflict with, or are expressly prohibited by, the GPL. |
| 22 | * |
| 23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
| 27 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 33 | * SUCH DAMAGE. |
| 34 | * |
| 35 | * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $ |
| 36 | */ |
| 37 | |
| 38 | #include "aic7xxx.reg" |
| 39 | #include "scsi_message.h" |
| 40 | |
| 41 | /* |
| 42 | * A few words on the waiting SCB list: |
| 43 | * After starting the selection hardware, we check for reconnecting targets |
| 44 | * as well as for our selection to complete just in case the reselection wins |
| 45 | * bus arbitration. The problem with this is that we must keep track of the |
| 46 | * SCB that we've already pulled from the QINFIFO and started the selection |
| 47 | * on just in case the reselection wins so that we can retry the selection at |
| 48 | * a later time. This problem cannot be resolved by holding a single entry |
| 49 | * in scratch ram since a reconnecting target can request sense and this will |
| 50 | * create yet another SCB waiting for selection. The solution used here is to |
| 51 | * use byte 27 of the SCB as a pseudo-next pointer and to thread a list |
| 52 | * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, |
| 53 | * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to |
| 54 | * this list everytime a request sense occurs or after completing a non-tagged |
| 55 | * command for which a second SCB has been queued. The sequencer will |
| 56 | * automatically consume the entries. |
| 57 | */ |
| 58 | |
| 59 | reset: |
| 60 | clr SCSISIGO; /* De-assert BSY */ |
| 61 | and SXFRCTL1, ~BITBUCKET; |
| 62 | /* Always allow reselection */ |
| 63 | mvi SCSISEQ, ENRSELI|ENAUTOATNP; |
| 64 | |
| 65 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 66 | /* Ensure that no DMA operations are in progress */ |
| 67 | clr CCSGCTL; |
| 68 | clr CCSCBCTL; |
| 69 | } |
| 70 | |
| 71 | call clear_target_state; |
| 72 | poll_for_work: |
| 73 | and SXFRCTL0, ~SPIOEN; |
| 74 | if ((p->features & AHC_QUEUE_REGS) == 0) { |
| 75 | mov A, QINPOS; |
| 76 | } |
| 77 | poll_for_work_loop: |
| 78 | if ((p->features & AHC_QUEUE_REGS) == 0) { |
| 79 | and SEQCTL, ~PAUSEDIS; |
| 80 | } |
| 81 | test SSTAT0, SELDO|SELDI jnz selection; |
| 82 | test SCSISEQ, ENSELO jnz poll_for_work; |
| 83 | if ((p->features & AHC_TWIN) != 0) { |
| 84 | /* |
| 85 | * Twin channel devices cannot handle things like SELTO |
| 86 | * interrupts on the "background" channel. So, if we |
| 87 | * are selecting, keep polling the current channel util |
| 88 | * either a selection or reselection occurs. |
| 89 | */ |
| 90 | xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ |
| 91 | test SSTAT0, SELDO|SELDI jnz selection; |
| 92 | test SCSISEQ, ENSELO jnz poll_for_work; |
| 93 | xor SBLKCTL,SELBUSB; /* Toggle back */ |
| 94 | } |
| 95 | cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; |
| 96 | test_queue: |
| 97 | /* Has the driver posted any work for us? */ |
| 98 | if ((p->features & AHC_QUEUE_REGS) != 0) { |
| 99 | test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; |
| 100 | mov NONE, SNSCB_QOFF; |
| 101 | inc QINPOS; |
| 102 | } else { |
| 103 | or SEQCTL, PAUSEDIS; |
| 104 | cmp KERNEL_QINPOS, A je poll_for_work_loop; |
| 105 | inc QINPOS; |
| 106 | and SEQCTL, ~PAUSEDIS; |
| 107 | } |
| 108 | |
| 109 | /* |
| 110 | * We have at least one queued SCB now and we don't have any |
| 111 | * SCBs in the list of SCBs awaiting selection. If we have |
| 112 | * any SCBs available for use, pull the tag from the QINFIFO |
| 113 | * and get to work on it. |
| 114 | */ |
| 115 | if ((p->flags & AHC_PAGESCBS) != 0) { |
| 116 | mov ALLZEROS call get_free_or_disc_scb; |
| 117 | } |
| 118 | |
| 119 | dequeue_scb: |
| 120 | add A, -1, QINPOS; |
| 121 | mvi QINFIFO_OFFSET call fetch_byte; |
| 122 | |
| 123 | if ((p->flags & AHC_PAGESCBS) == 0) { |
| 124 | /* In the non-paging case, the SCBID == hardware SCB index */ |
| 125 | mov SCBPTR, RETURN_2; |
| 126 | } |
| 127 | dma_queued_scb: |
| 128 | /* |
| 129 | * DMA the SCB from host ram into the current SCB location. |
| 130 | */ |
| 131 | mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; |
| 132 | mov RETURN_2 call dma_scb; |
| 133 | |
| 134 | /* |
| 135 | * Preset the residual fields in case we never go through a data phase. |
| 136 | * This isn't done by the host so we can avoid a DMA to clear these |
| 137 | * fields for the normal case of I/O that completes without underrun |
| 138 | * or overrun conditions. |
| 139 | */ |
| 140 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 141 | bmov SCB_RESID_DCNT, SCB_DATACNT, 3; |
| 142 | } else { |
| 143 | mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; |
| 144 | mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; |
| 145 | mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; |
| 146 | } |
| 147 | mov SCB_RESID_SGCNT, SCB_SGCOUNT; |
| 148 | |
| 149 | start_scb: |
| 150 | /* |
| 151 | * Place us on the waiting list in case our selection |
| 152 | * doesn't win during bus arbitration. |
| 153 | */ |
| 154 | mov SCB_NEXT,WAITING_SCBH; |
| 155 | mov WAITING_SCBH, SCBPTR; |
| 156 | start_waiting: |
| 157 | /* |
| 158 | * Pull the first entry off of the waiting SCB list. |
| 159 | */ |
| 160 | mov SCBPTR, WAITING_SCBH; |
| 161 | call start_selection; |
| 162 | jmp poll_for_work; |
| 163 | |
| 164 | start_selection: |
| 165 | if ((p->features & AHC_TWIN) != 0) { |
| 166 | and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ |
| 167 | and A,SELBUSB,SCB_TCL; /* Get new channel bit */ |
| 168 | or SINDEX,A; |
| 169 | mov SBLKCTL,SINDEX; /* select channel */ |
| 170 | } |
| 171 | initialize_scsiid: |
| 172 | if ((p->features & AHC_ULTRA2) != 0) { |
| 173 | and A, TID, SCB_TCL; /* Get target ID */ |
| 174 | and SCSIID_ULTRA2, OID; /* Clear old target */ |
| 175 | or SCSIID_ULTRA2, A; |
| 176 | } else { |
| 177 | and A, TID, SCB_TCL; /* Get target ID */ |
| 178 | and SCSIID, OID; /* Clear old target */ |
| 179 | or SCSIID, A; |
| 180 | } |
| 181 | mov SCSIDATL, ALLZEROS; /* clear out the latched */ |
| 182 | /* data register, this */ |
| 183 | /* fixes a bug on some */ |
| 184 | /* controllers where the */ |
| 185 | /* last byte written to */ |
| 186 | /* this register can leak */ |
| 187 | /* onto the data bus at */ |
| 188 | /* bad times, such as during */ |
| 189 | /* selection timeouts */ |
| 190 | mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; |
| 191 | |
| 192 | /* |
| 193 | * Initialize Ultra mode setting and clear the SCSI channel. |
| 194 | * SINDEX should contain any additional bit's the client wants |
| 195 | * set in SXFRCTL0. |
| 196 | */ |
| 197 | initialize_channel: |
| 198 | or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; |
| 199 | if ((p->features & AHC_ULTRA) != 0) { |
| 200 | ultra: |
| 201 | mvi SINDEX, ULTRA_ENB+1; |
| 202 | test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ |
| 203 | dec SINDEX; |
| 204 | ultra_2: |
| 205 | mov FUNCTION1,SAVED_TCL; |
| 206 | mov A,FUNCTION1; |
| 207 | test SINDIR, A jz ndx_dtr; |
| 208 | or SXFRCTL0, FAST20; |
| 209 | } |
| 210 | /* |
| 211 | * Initialize SCSIRATE with the appropriate value for this target. |
| 212 | * The SCSIRATE settings for each target are stored in an array |
| 213 | * based at TARG_SCSIRATE. |
| 214 | */ |
| 215 | ndx_dtr: |
| 216 | shr A,4,SAVED_TCL; |
| 217 | if ((p->features & AHC_TWIN) != 0) { |
| 218 | test SBLKCTL,SELBUSB jz ndx_dtr_2; |
| 219 | or SAVED_TCL, SELBUSB; |
| 220 | or A,0x08; /* Channel B entries add 8 */ |
| 221 | ndx_dtr_2: |
| 222 | } |
| 223 | |
| 224 | if ((p->features & AHC_ULTRA2) != 0) { |
| 225 | add SINDEX, TARG_OFFSET, A; |
| 226 | mov SCSIOFFSET, SINDIR; |
| 227 | } |
| 228 | |
| 229 | add SINDEX,TARG_SCSIRATE,A; |
| 230 | mov SCSIRATE,SINDIR ret; |
| 231 | |
| 232 | |
| 233 | selection: |
| 234 | test SSTAT0,SELDO jnz select_out; |
| 235 | /* |
| 236 | * Reselection has been initiated by a target. Make a note that we've been |
| 237 | * reselected, but haven't seen an IDENTIFY message from the target yet. |
| 238 | */ |
| 239 | initiator_reselect: |
| 240 | mvi CLRSINT0, CLRSELDI; |
| 241 | /* XXX test for and handle ONE BIT condition */ |
| 242 | and SAVED_TCL, SELID_MASK, SELID; |
| 243 | mvi CLRSINT1,CLRBUSFREE; |
| 244 | or SIMODE1, ENBUSFREE; /* |
| 245 | * We aren't expecting a |
| 246 | * bus free, so interrupt |
| 247 | * the kernel driver if it |
| 248 | * happens. |
| 249 | */ |
| 250 | mvi SPIOEN call initialize_channel; |
| 251 | mvi MSG_OUT, MSG_NOOP; /* No message to send */ |
| 252 | jmp ITloop; |
| 253 | |
| 254 | /* |
| 255 | * After the selection, remove this SCB from the "waiting SCB" |
| 256 | * list. This is achieved by simply moving our "next" pointer into |
| 257 | * WAITING_SCBH. Our next pointer will be set to null the next time this |
| 258 | * SCB is used, so don't bother with it now. |
| 259 | */ |
| 260 | select_out: |
| 261 | /* Turn off the selection hardware */ |
| 262 | mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* |
| 263 | * ATN on parity errors |
| 264 | * for "in" phases |
| 265 | */ |
| 266 | mvi CLRSINT0, CLRSELDO; |
| 267 | mov SCBPTR, WAITING_SCBH; |
| 268 | mov WAITING_SCBH,SCB_NEXT; |
| 269 | mov SAVED_TCL, SCB_TCL; |
| 270 | mvi CLRSINT1,CLRBUSFREE; |
| 271 | or SIMODE1, ENBUSFREE; /* |
| 272 | * We aren't expecting a |
| 273 | * bus free, so interrupt |
| 274 | * the kernel driver if it |
| 275 | * happens. |
| 276 | */ |
| 277 | mvi SPIOEN call initialize_channel; |
| 278 | /* |
| 279 | * As soon as we get a successful selection, the target should go |
| 280 | * into the message out phase since we have ATN asserted. |
| 281 | */ |
| 282 | mvi MSG_OUT, MSG_IDENTIFYFLAG; |
| 283 | or SEQ_FLAGS, IDENTIFY_SEEN; |
| 284 | |
| 285 | /* |
| 286 | * Main loop for information transfer phases. Wait for the target |
| 287 | * to assert REQ before checking MSG, C/D and I/O for the bus phase. |
| 288 | */ |
| 289 | ITloop: |
| 290 | call phase_lock; |
| 291 | |
| 292 | mov A, LASTPHASE; |
| 293 | |
| 294 | test A, ~P_DATAIN jz p_data; |
| 295 | cmp A,P_COMMAND je p_command; |
| 296 | cmp A,P_MESGOUT je p_mesgout; |
| 297 | cmp A,P_STATUS je p_status; |
| 298 | cmp A,P_MESGIN je p_mesgin; |
| 299 | |
| 300 | mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ |
| 301 | jmp ITloop; /* Try reading the bus again. */ |
| 302 | |
| 303 | await_busfree: |
| 304 | and SIMODE1, ~ENBUSFREE; |
| 305 | call clear_target_state; |
| 306 | mov NONE, SCSIDATL; /* Ack the last byte */ |
| 307 | and SXFRCTL0, ~SPIOEN; |
| 308 | test SSTAT1,REQINIT|BUSFREE jz .; |
| 309 | test SSTAT1, BUSFREE jnz poll_for_work; |
| 310 | mvi INTSTAT, BAD_PHASE; |
| 311 | |
| 312 | clear_target_state: |
| 313 | /* |
| 314 | * We assume that the kernel driver may reset us |
| 315 | * at any time, even in the middle of a DMA, so |
| 316 | * clear DFCNTRL too. |
| 317 | */ |
| 318 | clr DFCNTRL; |
| 319 | |
| 320 | /* |
| 321 | * We don't know the target we will connect to, |
| 322 | * so default to narrow transfers to avoid |
| 323 | * parity problems. |
| 324 | */ |
| 325 | if ((p->features & AHC_ULTRA2) != 0) { |
| 326 | bmov SCSIRATE, ALLZEROS, 2; |
| 327 | } else { |
| 328 | clr SCSIRATE; |
| 329 | and SXFRCTL0, ~(FAST20); |
| 330 | } |
| 331 | mvi LASTPHASE, P_BUSFREE; |
| 332 | /* clear target specific flags */ |
| 333 | clr SEQ_FLAGS ret; |
| 334 | |
| 335 | |
| 336 | data_phase_reinit: |
| 337 | /* |
| 338 | * If we re-enter the data phase after going through another phase, the |
| 339 | * STCNT may have been cleared, so restore it from the residual field. |
| 340 | * On Ultra2, we have to put it into the HCNT field because we have to |
| 341 | * drop the data down into the shadow layer via the preload ability. |
| 342 | */ |
| 343 | if ((p->features & AHC_ULTRA2) != 0) { |
| 344 | bmov HADDR, SHADDR, 4; |
| 345 | bmov HCNT, SCB_RESID_DCNT, 3; |
| 346 | } |
| 347 | if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { |
| 348 | bmov STCNT, SCB_RESID_DCNT, 3; |
| 349 | } |
| 350 | if ((p->features & AHC_CMD_CHAN) == 0) { |
| 351 | mvi DINDEX, STCNT; |
| 352 | mvi SCB_RESID_DCNT call bcopy_3; |
| 353 | } |
| 354 | jmp data_phase_loop; |
| 355 | p_data: |
| 356 | if ((p->features & AHC_ULTRA2) != 0) { |
| 357 | mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; |
| 358 | } else { |
| 359 | mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; |
| 360 | } |
| 361 | test LASTPHASE, IOI jnz . + 2; |
| 362 | or DMAPARAMS, DIRECTION; |
| 363 | call assert; /* |
| 364 | * Ensure entering a data |
| 365 | * phase is okay - seen identify, etc. |
| 366 | */ |
| 367 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 368 | mvi CCSGADDR, CCSGADDR_MAX; |
| 369 | } |
| 370 | |
| 371 | test SEQ_FLAGS, DPHASE jnz data_phase_reinit; |
| 372 | or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ |
| 373 | /* |
| 374 | * Initialize the DMA address and counter from the SCB. |
| 375 | * Also set SG_COUNT and SG_NEXT in memory since we cannot |
| 376 | * modify the values in the SCB itself until we see a |
| 377 | * save data pointers message. |
| 378 | */ |
| 379 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 380 | bmov HADDR, SCB_DATAPTR, 7; |
| 381 | bmov SG_COUNT, SCB_SGCOUNT, 5; |
| 382 | if ((p->features & AHC_ULTRA2) == 0) { |
| 383 | bmov STCNT, HCNT, 3; |
| 384 | } |
| 385 | } else { |
| 386 | mvi DINDEX, HADDR; |
| 387 | mvi SCB_DATAPTR call bcopy_7; |
| 388 | call set_stcnt_from_hcnt; |
| 389 | mvi DINDEX, SG_COUNT; |
| 390 | mvi SCB_SGCOUNT call bcopy_5; |
| 391 | } |
| 392 | data_phase_loop: |
| 393 | /* Guard against overruns */ |
| 394 | test SG_COUNT, 0xff jnz data_phase_inbounds; |
| 395 | /* |
| 396 | * Turn on 'Bit Bucket' mode, set the transfer count to |
| 397 | * 16meg and let the target run until it changes phase. |
| 398 | * When the transfer completes, notify the host that we |
| 399 | * had an overrun. |
| 400 | */ |
| 401 | or SXFRCTL1,BITBUCKET; |
| 402 | and DMAPARAMS, ~(HDMAEN|SDMAEN); |
| 403 | if ((p->features & AHC_ULTRA2) != 0) { |
| 404 | bmov HCNT, ALLONES, 3; |
| 405 | } |
| 406 | if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { |
| 407 | bmov STCNT, ALLONES, 3; |
| 408 | } |
| 409 | if ((p->features & AHC_CMD_CHAN) == 0) { |
| 410 | mvi STCNT[0], 0xFF; |
| 411 | mvi STCNT[1], 0xFF; |
| 412 | mvi STCNT[2], 0xFF; |
| 413 | } |
| 414 | |
| 415 | data_phase_inbounds: |
| 416 | /* If we are the last SG block, tell the hardware. */ |
| 417 | if ((p->features & AHC_ULTRA2) != 0) { |
| 418 | shl A, 2, SG_COUNT; |
| 419 | cmp SG_COUNT,0x01 jne data_phase_wideodd; |
| 420 | or A, LAST_SEG; |
| 421 | } else { |
| 422 | cmp SG_COUNT,0x01 jne data_phase_wideodd; |
| 423 | and DMAPARAMS, ~WIDEODD; |
| 424 | } |
| 425 | data_phase_wideodd: |
| 426 | if ((p->features & AHC_ULTRA2) != 0) { |
| 427 | mov SG_CACHEPTR, A; |
| 428 | mov DFCNTRL, DMAPARAMS; /* start the operation */ |
| 429 | test SXFRCTL1, BITBUCKET jnz data_phase_overrun; |
| 430 | u2_preload_wait: |
| 431 | test SSTAT1, PHASEMIS jnz u2_phasemis; |
| 432 | test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; |
| 433 | } else { |
| 434 | mov DMAPARAMS call dma; |
| 435 | data_phase_dma_done: |
| 436 | /* Go tell the host about any overruns */ |
| 437 | test SXFRCTL1,BITBUCKET jnz data_phase_overrun; |
| 438 | |
| 439 | /* Exit if we had an underrun. dma clears SINDEX in this case. */ |
| 440 | test SINDEX,0xff jz data_phase_finish; |
| 441 | } |
| 442 | /* |
| 443 | * Advance the scatter-gather pointers |
| 444 | */ |
| 445 | sg_advance: |
| 446 | if ((p->features & AHC_ULTRA2) != 0) { |
| 447 | cmp SG_COUNT, 0x01 je u2_data_phase_finish; |
| 448 | } else { |
| 449 | dec SG_COUNT; |
| 450 | test SG_COUNT, 0xff jz data_phase_finish; |
| 451 | } |
| 452 | |
| 453 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 454 | |
| 455 | /* |
| 456 | * Do we have any prefetch left??? |
| 457 | */ |
| 458 | cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; |
| 459 | |
| 460 | /* |
| 461 | * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. |
| 462 | */ |
| 463 | add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; |
| 464 | mvi A, CCSGADDR_MAX; |
| 465 | jc . + 2; |
| 466 | shl A, 3, SG_COUNT; |
| 467 | mov CCHCNT, A; |
| 468 | bmov CCHADDR, SG_NEXT, 4; |
| 469 | mvi CCSGCTL, CCSGEN|CCSGRESET; |
| 470 | test CCSGCTL, CCSGDONE jz .; |
| 471 | and CCSGCTL, ~CCSGEN; |
| 472 | test CCSGCTL, CCSGEN jnz .; |
| 473 | mvi CCSGCTL, CCSGRESET; |
| 474 | prefetch_avail: |
| 475 | bmov HADDR, CCSGRAM, 8; |
| 476 | if ((p->features & AHC_ULTRA2) == 0) { |
| 477 | bmov STCNT, HCNT, 3; |
| 478 | } else { |
| 479 | dec SG_COUNT; |
| 480 | } |
| 481 | } else { |
| 482 | mvi DINDEX, HADDR; |
| 483 | mvi SG_NEXT call bcopy_4; |
| 484 | |
| 485 | mvi HCNT[0],SG_SIZEOF; |
| 486 | clr HCNT[1]; |
| 487 | clr HCNT[2]; |
| 488 | |
| 489 | or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; |
| 490 | |
| 491 | call dma_finish; |
| 492 | |
| 493 | /* |
| 494 | * Copy data from FIFO into SCB data pointer and data count. |
| 495 | * This assumes that the SG segments are of the form: |
| 496 | * struct ahc_dma_seg { |
| 497 | * u_int32_t addr; four bytes, little-endian order |
| 498 | * u_int32_t len; four bytes, little endian order |
| 499 | * }; |
| 500 | */ |
| 501 | mvi DINDEX, HADDR; |
| 502 | call dfdat_in_7; |
| 503 | call set_stcnt_from_hcnt; |
| 504 | } |
| 505 | /* Advance the SG pointer */ |
| 506 | clr A; /* add sizeof(struct scatter) */ |
| 507 | add SG_NEXT[0],SG_SIZEOF; |
| 508 | adc SG_NEXT[1],A; |
| 509 | |
| 510 | if ((p->features & AHC_ULTRA2) != 0) { |
| 511 | jmp data_phase_loop; |
| 512 | } else { |
| 513 | test SSTAT1, REQINIT jz .; |
| 514 | test SSTAT1,PHASEMIS jz data_phase_loop; |
| 515 | } |
| 516 | |
| 517 | |
| 518 | /* |
| 519 | * We've loaded all of our segments into the preload layer. Now, we simply |
| 520 | * have to wait for it to finish or for us to get a phasemis. And, since |
| 521 | * we'll get a phasemis if we do finish, all we really need to do is wait |
| 522 | * for a phasemis then check if we did actually complete all the segments. |
| 523 | */ |
| 524 | if ((p->features & AHC_ULTRA2) != 0) { |
| 525 | u2_data_phase_finish: |
| 526 | test SSTAT1, PHASEMIS jnz u2_phasemis; |
| 527 | test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; |
| 528 | clr SG_COUNT; |
| 529 | test SSTAT1, REQINIT jz .; |
| 530 | test SSTAT1, PHASEMIS jz data_phase_loop; |
| 531 | u2_phasemis: |
| 532 | call ultra2_dmafinish; |
| 533 | test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; |
| 534 | test SSTAT2, SHVALID jnz u2_fixup_residual; |
| 535 | mvi INTSTAT, SEQ_SG_FIXUP; |
| 536 | jmp data_phase_finish; |
| 537 | u2_fixup_residual: |
| 538 | shr ARG_1, 2, SG_CACHEPTR; |
| 539 | u2_phasemis_loop: |
| 540 | and A, 0x3f, SG_COUNT; |
| 541 | cmp ARG_1, A je data_phase_finish; |
| 542 | /* |
| 543 | * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT |
| 544 | */ |
| 545 | clr A; |
| 546 | add SG_NEXT[0], -SG_SIZEOF; |
| 547 | adc SG_NEXT[1], 0xff; |
| 548 | inc SG_COUNT; |
| 549 | jmp u2_phasemis_loop; |
| 550 | } |
| 551 | |
| 552 | data_phase_finish: |
| 553 | /* |
| 554 | * After a DMA finishes, save the SG and STCNT residuals back into the SCB |
| 555 | * We use STCNT instead of HCNT, since it's a reflection of how many bytes |
| 556 | * were transferred on the SCSI (as opposed to the host) bus. |
| 557 | */ |
| 558 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 559 | bmov SCB_RESID_DCNT, STCNT, 3; |
| 560 | mov SCB_RESID_SGCNT, SG_COUNT; |
| 561 | if ((p->features & AHC_ULTRA2) != 0) { |
| 562 | or SXFRCTL0, CLRSTCNT|CLRCHN; |
| 563 | } |
| 564 | } else { |
| 565 | mov SCB_RESID_DCNT[0],STCNT[0]; |
| 566 | mov SCB_RESID_DCNT[1],STCNT[1]; |
| 567 | mov SCB_RESID_DCNT[2],STCNT[2]; |
| 568 | mov SCB_RESID_SGCNT, SG_COUNT; |
| 569 | } |
| 570 | |
| 571 | jmp ITloop; |
| 572 | |
| 573 | data_phase_overrun: |
| 574 | /* |
| 575 | * Turn off BITBUCKET mode and notify the host |
| 576 | */ |
| 577 | if ((p->features & AHC_ULTRA2) != 0) { |
| 578 | /* |
| 579 | * Wait for the target to quit transferring data on the SCSI bus |
| 580 | */ |
| 581 | test SSTAT1, PHASEMIS jz .; |
| 582 | call ultra2_dmafinish; |
| 583 | } |
| 584 | and SXFRCTL1, ~BITBUCKET; |
| 585 | mvi INTSTAT,DATA_OVERRUN; |
| 586 | jmp ITloop; |
| 587 | |
| 588 | |
| 589 | |
| 590 | |
| 591 | /* |
| 592 | * Actually turn off the DMA hardware, save our current position into the |
| 593 | * proper residual variables, wait for the next REQ signal, then jump to |
| 594 | * the ITloop. Jumping to the ITloop ensures that if we happen to get |
| 595 | * brought into the data phase again (or are still in it after our last |
| 596 | * segment) that we will properly signal an overrun to the kernel. |
| 597 | */ |
| 598 | if ((p->features & AHC_ULTRA2) != 0) { |
| 599 | ultra2_dmafinish: |
| 600 | test DFCNTRL, DIRECTION jnz ultra2_dmahalt; |
| 601 | and DFCNTRL, ~SCSIEN; |
| 602 | test DFCNTRL, SCSIEN jnz .; |
| 603 | if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { |
| 604 | or DFCNTRL, FIFOFLUSH; |
| 605 | } |
| 606 | ultra2_dmafifoflush: |
| 607 | if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { |
| 608 | /* |
| 609 | * hardware bug alert! This needless set of jumps |
| 610 | * works around a glitch in the silicon. When the |
| 611 | * PCI DMA fifo goes empty, but there is still SCSI |
| 612 | * data to be flushed into the PCI DMA fifo (and from |
| 613 | * there on into main memory), the FIFOEMP bit will |
| 614 | * come on between the time when the PCI DMA buffer |
| 615 | * went empty and the next bit of data is copied from |
| 616 | * the SCSI fifo into the PCI fifo. It should only |
| 617 | * come on when both FIFOs (meaning the entire FIFO |
| 618 | * chain) are emtpy. Since it can take up to 4 cycles |
| 619 | * for new data to be copied from the SCSI fifo into |
| 620 | * the PCI fifo, testing for FIFOEMP status for 4 |
| 621 | * extra times gives the needed time for any |
| 622 | * remaining SCSI fifo data to be put in the PCI fifo |
| 623 | * before we declare it *truly* empty. |
| 624 | */ |
| 625 | test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; |
| 626 | test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; |
| 627 | test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; |
| 628 | test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; |
| 629 | } |
| 630 | test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; |
| 631 | test DFSTATUS, MREQPEND jnz .; |
| 632 | ultra2_dmahalt: |
| 633 | and DFCNTRL, ~(HDMAEN|SCSIEN); |
| 634 | test DFCNTRL, (HDMAEN|SCSIEN) jnz .; |
| 635 | ret; |
| 636 | } |
| 637 | |
| 638 | /* |
| 639 | * Command phase. Set up the DMA registers and let 'er rip. |
| 640 | */ |
| 641 | p_command: |
| 642 | call assert; |
| 643 | |
| 644 | /* |
| 645 | * Load HADDR and HCNT. |
| 646 | */ |
| 647 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 648 | bmov HADDR, SCB_CMDPTR, 5; |
| 649 | bmov HCNT[1], ALLZEROS, 2; |
| 650 | if ((p->features & AHC_ULTRA2) == 0) { |
| 651 | bmov STCNT, HCNT, 3; |
| 652 | } |
| 653 | } else { |
| 654 | mvi DINDEX, HADDR; |
| 655 | mvi SCB_CMDPTR call bcopy_5; |
| 656 | clr HCNT[1]; |
| 657 | clr HCNT[2]; |
| 658 | call set_stcnt_from_hcnt; |
| 659 | } |
| 660 | |
| 661 | if ((p->features & AHC_ULTRA2) == 0) { |
| 662 | mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; |
| 663 | } else { |
| 664 | mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); |
| 665 | test SSTAT0, SDONE jnz .; |
| 666 | p_command_dma_loop: |
| 667 | test SSTAT0, SDONE jnz p_command_ultra2_dma_done; |
| 668 | test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ |
| 669 | p_command_ultra2_dma_done: |
| 670 | test SCSISIGI, REQI jz p_command_ultra2_shutdown; |
| 671 | test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; |
| 672 | p_command_ultra2_shutdown: |
| 673 | and DFCNTRL, ~(HDMAEN|SCSIEN); |
| 674 | test DFCNTRL, (HDMAEN|SCSIEN) jnz .; |
| 675 | or SXFRCTL0, CLRSTCNT|CLRCHN; |
| 676 | } |
| 677 | jmp ITloop; |
| 678 | |
| 679 | /* |
| 680 | * Status phase. Wait for the data byte to appear, then read it |
| 681 | * and store it into the SCB. |
| 682 | */ |
| 683 | p_status: |
| 684 | call assert; |
| 685 | |
| 686 | mov SCB_TARGET_STATUS, SCSIDATL; |
| 687 | jmp ITloop; |
| 688 | |
| 689 | /* |
| 690 | * Message out phase. If MSG_OUT is 0x80, build I full indentify message |
| 691 | * sequence and send it to the target. In addition, if the MK_MESSAGE bit |
| 692 | * is set in the SCB_CONTROL byte, interrupt the host and allow it to send |
| 693 | * it's own message. |
| 694 | * |
| 695 | * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. |
| 696 | * This is done to allow the hsot to send messages outside of an identify |
| 697 | * sequence while protecting the seqencer from testing the MK_MESSAGE bit |
| 698 | * on an SCB that might not be for the current nexus. (For example, a |
| 699 | * BDR message in responce to a bad reselection would leave us pointed to |
| 700 | * an SCB that doesn't have anything to do with the current target). |
| 701 | * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, |
| 702 | * bus device reset). |
| 703 | * |
| 704 | * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, |
| 705 | * in case the target decides to put us in this phase for some strange |
| 706 | * reason. |
| 707 | */ |
| 708 | p_mesgout_retry: |
| 709 | or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ |
| 710 | p_mesgout: |
| 711 | mov SINDEX, MSG_OUT; |
| 712 | cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; |
| 713 | p_mesgout_identify: |
| 714 | if ((p->features & AHC_WIDE) != 0) { |
| 715 | and SINDEX,0xf,SCB_TCL; /* lun */ |
| 716 | } else { |
| 717 | and SINDEX,0x7,SCB_TCL; /* lun */ |
| 718 | } |
| 719 | and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ |
| 720 | or SINDEX,A; /* or in disconnect privledge */ |
| 721 | or SINDEX,MSG_IDENTIFYFLAG; |
| 722 | p_mesgout_mk_message: |
| 723 | test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; |
| 724 | mov SCSIDATL, SINDEX; /* Send the last byte */ |
| 725 | jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */ |
| 726 | /* |
| 727 | * Send a tag message if TAG_ENB is set in the SCB control block. |
| 728 | * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. |
| 729 | */ |
| 730 | p_mesgout_tag: |
| 731 | test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; |
| 732 | mov SCSIDATL, SINDEX; /* Send the identify message */ |
| 733 | call phase_lock; |
| 734 | cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; |
| 735 | and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; |
| 736 | call phase_lock; |
| 737 | cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; |
| 738 | mov SCB_TAG jmp p_mesgout_onebyte; |
| 739 | /* |
| 740 | * Interrupt the driver, and allow it to send a message |
| 741 | * if it asks. |
| 742 | */ |
| 743 | p_mesgout_from_host: |
| 744 | cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; |
| 745 | mvi INTSTAT,AWAITING_MSG; |
| 746 | nop; |
| 747 | /* |
| 748 | * Did the host detect a phase change? |
| 749 | */ |
| 750 | cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done; |
| 751 | |
| 752 | p_mesgout_onebyte: |
| 753 | mvi CLRSINT1, CLRATNO; |
| 754 | mov SCSIDATL, SINDEX; |
| 755 | |
| 756 | /* |
| 757 | * If the next bus phase after ATN drops is a message out, it means |
| 758 | * that the target is requesting that the last message(s) be resent. |
| 759 | */ |
| 760 | call phase_lock; |
| 761 | cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; |
| 762 | |
| 763 | p_mesgout_done: |
| 764 | mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ |
| 765 | mov LAST_MSG, MSG_OUT; |
| 766 | cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; |
| 767 | and SCB_CONTROL, ~MK_MESSAGE; |
| 768 | mvi MSG_OUT, MSG_NOOP; /* No message left */ |
| 769 | jmp ITloop; |
| 770 | |
| 771 | /* |
| 772 | * Message in phase. Bytes are read using Automatic PIO mode. |
| 773 | */ |
| 774 | p_mesgin: |
| 775 | mvi ACCUM call inb_first; /* read the 1st message byte */ |
| 776 | |
| 777 | test A,MSG_IDENTIFYFLAG jnz mesgin_identify; |
| 778 | cmp A,MSG_DISCONNECT je mesgin_disconnect; |
| 779 | cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; |
| 780 | cmp ALLZEROS,A je mesgin_complete; |
| 781 | cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; |
| 782 | cmp A,MSG_EXTENDED je mesgin_extended; |
| 783 | cmp A,MSG_MESSAGE_REJECT je mesgin_reject; |
| 784 | cmp A,MSG_NOOP je mesgin_done; |
| 785 | cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue; |
| 786 | |
| 787 | rej_mesgin: |
| 788 | /* |
| 789 | * We have no idea what this message in is, so we issue a message reject |
| 790 | * and hope for the best. In any case, rejection should be a rare |
| 791 | * occurrence - signal the driver when it happens. |
| 792 | */ |
| 793 | mvi INTSTAT,SEND_REJECT; /* let driver know */ |
| 794 | |
| 795 | mvi MSG_MESSAGE_REJECT call mk_mesg; |
| 796 | |
| 797 | mesgin_done: |
| 798 | mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ |
| 799 | jmp ITloop; |
| 800 | |
| 801 | |
| 802 | mesgin_complete: |
| 803 | /* |
| 804 | * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, |
| 805 | * and trigger a completion interrupt. Before doing so, check to see if there |
| 806 | * is a residual or the status byte is something other than STATUS_GOOD (0). |
| 807 | * In either of these conditions, we upload the SCB back to the host so it can |
| 808 | * process this information. In the case of a non zero status byte, we |
| 809 | * additionally interrupt the kernel driver synchronously, allowing it to |
| 810 | * decide if sense should be retrieved. If the kernel driver wishes to request |
| 811 | * sense, it will fill the kernel SCB with a request sense command and set |
| 812 | * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload |
| 813 | * the SCB, and process it as the next command by adding it to the waiting list. |
| 814 | * If the kernel driver does not wish to request sense, it need only clear |
| 815 | * RETURN_1, and the command is allowed to complete normally. We don't bother |
| 816 | * to post to the QOUTFIFO in the error cases since it would require extra |
| 817 | * work in the kernel driver to ensure that the entry was removed before the |
| 818 | * command complete code tried processing it. |
| 819 | */ |
| 820 | |
| 821 | /* |
| 822 | * First check for residuals |
| 823 | */ |
| 824 | test SCB_RESID_SGCNT,0xff jnz upload_scb; |
| 825 | test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ |
| 826 | upload_scb: |
| 827 | mvi DMAPARAMS, FIFORESET; |
| 828 | mov SCB_TAG call dma_scb; |
| 829 | check_status: |
| 830 | test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ |
| 831 | mvi INTSTAT,BAD_STATUS; /* let driver know */ |
| 832 | nop; |
| 833 | cmp RETURN_1, SEND_SENSE jne complete; |
| 834 | /* This SCB becomes the next to execute as it will retrieve sense */ |
| 835 | mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; |
| 836 | mov SCB_TAG call dma_scb; |
| 837 | add_to_waiting_list: |
| 838 | mov SCB_NEXT,WAITING_SCBH; |
| 839 | mov WAITING_SCBH, SCBPTR; |
| 840 | /* |
| 841 | * Prepare our selection hardware before the busfree so we have a |
| 842 | * high probability of winning arbitration. |
| 843 | */ |
| 844 | call start_selection; |
| 845 | jmp await_busfree; |
| 846 | |
| 847 | complete: |
| 848 | /* If we are untagged, clear our address up in host ram */ |
| 849 | test SCB_CONTROL, TAG_ENB jnz complete_post; |
| 850 | mov A, SAVED_TCL; |
| 851 | mvi UNTAGGEDSCB_OFFSET call post_byte_setup; |
| 852 | mvi SCB_LIST_NULL call post_byte; |
| 853 | |
| 854 | complete_post: |
| 855 | /* Post the SCB and issue an interrupt */ |
| 856 | if ((p->features & AHC_QUEUE_REGS) != 0) { |
| 857 | mov A, SDSCB_QOFF; |
| 858 | } else { |
| 859 | mov A, QOUTPOS; |
| 860 | } |
| 861 | mvi QOUTFIFO_OFFSET call post_byte_setup; |
| 862 | mov SCB_TAG call post_byte; |
| 863 | if ((p->features & AHC_QUEUE_REGS) == 0) { |
| 864 | inc QOUTPOS; |
| 865 | } |
| 866 | mvi INTSTAT,CMDCMPLT; |
| 867 | |
| 868 | add_to_free_list: |
| 869 | call add_scb_to_free_list; |
| 870 | jmp await_busfree; |
| 871 | |
| 872 | /* |
| 873 | * Is it an extended message? Copy the message to our message buffer and |
| 874 | * notify the host. The host will tell us whether to reject this message, |
| 875 | * respond to it with the message that the host placed in our message buffer, |
| 876 | * or simply to do nothing. |
| 877 | */ |
| 878 | mesgin_extended: |
| 879 | mvi INTSTAT,EXTENDED_MSG; /* let driver know */ |
| 880 | jmp ITloop; |
| 881 | |
| 882 | /* |
| 883 | * Is it a disconnect message? Set a flag in the SCB to remind us |
| 884 | * and await the bus going free. |
| 885 | */ |
| 886 | mesgin_disconnect: |
| 887 | or SCB_CONTROL,DISCONNECTED; |
| 888 | call add_scb_to_disc_list; |
| 889 | jmp await_busfree; |
| 890 | |
| 891 | /* |
| 892 | * Save data pointers message: |
| 893 | * Copying RAM values back to SCB, for Save Data Pointers message, but |
| 894 | * only if we've actually been into a data phase to change them. This |
| 895 | * protects against bogus data in scratch ram and the residual counts |
| 896 | * since they are only initialized when we go into data_in or data_out. |
| 897 | */ |
| 898 | mesgin_sdptrs: |
| 899 | test SEQ_FLAGS, DPHASE jz mesgin_done; |
| 900 | /* |
| 901 | * The SCB SGPTR becomes the next one we'll download, |
| 902 | * and the SCB DATAPTR becomes the current SHADDR. |
| 903 | * Use the residual number since STCNT is corrupted by |
| 904 | * any message transfer. |
| 905 | */ |
| 906 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 907 | bmov SCB_SGCOUNT, SG_COUNT, 5; |
| 908 | bmov SCB_DATAPTR, SHADDR, 4; |
| 909 | bmov SCB_DATACNT, SCB_RESID_DCNT, 3; |
| 910 | } else { |
| 911 | mvi DINDEX, SCB_SGCOUNT; |
| 912 | mvi SG_COUNT call bcopy_5; |
| 913 | mvi DINDEX, SCB_DATAPTR; |
| 914 | mvi SHADDR call bcopy_4; |
| 915 | mvi SCB_RESID_DCNT call bcopy_3; |
| 916 | } |
| 917 | jmp mesgin_done; |
| 918 | |
| 919 | /* |
| 920 | * Restore pointers message? Data pointers are recopied from the |
| 921 | * SCB anytime we enter a data phase for the first time, so all |
| 922 | * we need to do is clear the DPHASE flag and let the data phase |
| 923 | * code do the rest. |
| 924 | */ |
| 925 | mesgin_rdptrs: |
| 926 | and SEQ_FLAGS, ~DPHASE; /* |
| 927 | * We'll reload them |
| 928 | * the next time through |
| 929 | * the dataphase. |
| 930 | */ |
| 931 | jmp mesgin_done; |
| 932 | |
| 933 | /* |
| 934 | * Identify message? For a reconnecting target, this tells us the lun |
| 935 | * that the reconnection is for - find the correct SCB and switch to it, |
| 936 | * clearing the "disconnected" bit so we don't "find" it by accident later. |
| 937 | */ |
| 938 | mesgin_identify: |
| 939 | |
| 940 | if ((p->features & AHC_WIDE) != 0) { |
| 941 | and A,0x0f; /* lun in lower four bits */ |
| 942 | } else { |
| 943 | and A,0x07; /* lun in lower three bits */ |
| 944 | } |
| 945 | or SAVED_TCL,A; /* SAVED_TCL should be complete now */ |
| 946 | |
| 947 | mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ |
| 948 | call get_untagged_SCBID; |
| 949 | cmp ARG_1, SCB_LIST_NULL je snoop_tag; |
| 950 | if ((p->flags & AHC_PAGESCBS) != 0) { |
| 951 | test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; |
| 952 | } |
| 953 | /* |
| 954 | * If the SCB was found in the disconnected list (as is |
| 955 | * always the case in non-paging scenarios), SCBPTR is already |
| 956 | * set to the correct SCB. So, simply setup the SCB and get |
| 957 | * on with things. |
| 958 | */ |
| 959 | mov SCBPTR call rem_scb_from_disc_list; |
| 960 | jmp setup_SCB; |
| 961 | /* |
| 962 | * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. |
| 963 | * If we get one, we use the tag returned to find the proper |
| 964 | * SCB. With SCB paging, this requires using search for both tagged |
| 965 | * and non-tagged transactions since the SCB may exist in any slot. |
| 966 | * If we're not using SCB paging, we can use the tag as the direct |
| 967 | * index to the SCB. |
| 968 | */ |
| 969 | snoop_tag: |
| 970 | mov NONE,SCSIDATL; /* ACK Identify MSG */ |
| 971 | snoop_tag_loop: |
| 972 | call phase_lock; |
| 973 | cmp LASTPHASE, P_MESGIN jne not_found; |
| 974 | cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; |
| 975 | get_tag: |
| 976 | mvi ARG_1 call inb_next; /* tag value */ |
| 977 | |
| 978 | use_retrieveSCB: |
| 979 | call retrieveSCB; |
| 980 | setup_SCB: |
| 981 | mov A, SAVED_TCL; |
| 982 | cmp SCB_TCL, A jne not_found_cleanup_scb; |
| 983 | test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; |
| 984 | and SCB_CONTROL,~DISCONNECTED; |
| 985 | or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ |
| 986 | /* See if the host wants to send a message upon reconnection */ |
| 987 | test SCB_CONTROL, MK_MESSAGE jz mesgin_done; |
| 988 | and SCB_CONTROL, ~MK_MESSAGE; |
| 989 | mvi HOST_MSG call mk_mesg; |
| 990 | jmp mesgin_done; |
| 991 | |
| 992 | not_found_cleanup_scb: |
| 993 | test SCB_CONTROL, DISCONNECTED jz . + 3; |
| 994 | call add_scb_to_disc_list; |
| 995 | jmp not_found; |
| 996 | call add_scb_to_free_list; |
| 997 | not_found: |
| 998 | mvi INTSTAT, NO_MATCH; |
| 999 | mvi MSG_BUS_DEV_RESET call mk_mesg; |
| 1000 | jmp mesgin_done; |
| 1001 | |
| 1002 | /* |
| 1003 | * Message reject? Let the kernel driver handle this. If we have an |
| 1004 | * outstanding WDTR or SDTR negotiation, assume that it's a response from |
| 1005 | * the target selecting 8bit or asynchronous transfer, otherwise just ignore |
| 1006 | * it since we have no clue what it pertains to. |
| 1007 | */ |
| 1008 | mesgin_reject: |
| 1009 | mvi INTSTAT, REJECT_MSG; |
| 1010 | jmp mesgin_done; |
| 1011 | |
| 1012 | /* |
| 1013 | * Wide Residue. We handle the simple cases, but pass of the one hard case |
| 1014 | * to the kernel (when the residue byte happened to cause us to advance our |
| 1015 | * sg element array, so we know have to back that advance out). |
| 1016 | */ |
| 1017 | mesgin_wide_residue: |
| 1018 | mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ |
| 1019 | /* the size byte */ |
| 1020 | /* |
| 1021 | * In order for this to be reliable, we have to do all sorts of horrible |
| 1022 | * magic in terms of resetting the datafifo and reloading the shadow layer |
| 1023 | * with the correct new values (so that a subsequent save data pointers |
| 1024 | * message will do the right thing). We let the kernel do that work. |
| 1025 | */ |
| 1026 | mvi INTSTAT, WIDE_RESIDUE; |
| 1027 | jmp mesgin_done; |
| 1028 | |
| 1029 | /* |
| 1030 | * [ ADD MORE MESSAGE HANDLING HERE ] |
| 1031 | */ |
| 1032 | |
| 1033 | /* |
| 1034 | * Locking the driver out, build a one-byte message passed in SINDEX |
| 1035 | * if there is no active message already. SINDEX is returned intact. |
| 1036 | */ |
| 1037 | mk_mesg: |
| 1038 | or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ |
| 1039 | mov MSG_OUT,SINDEX ret; |
| 1040 | |
| 1041 | /* |
| 1042 | * Functions to read data in Automatic PIO mode. |
| 1043 | * |
| 1044 | * According to Adaptec's documentation, an ACK is not sent on input from |
| 1045 | * the target until SCSIDATL is read from. So we wait until SCSIDATL is |
| 1046 | * latched (the usual way), then read the data byte directly off the bus |
| 1047 | * using SCSIBUSL. When we have pulled the ATN line, or we just want to |
| 1048 | * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI |
| 1049 | * spec guarantees that the target will hold the data byte on the bus until |
| 1050 | * we send our ACK. |
| 1051 | * |
| 1052 | * The assumption here is that these are called in a particular sequence, |
| 1053 | * and that REQ is already set when inb_first is called. inb_{first,next} |
| 1054 | * use the same calling convention as inb. |
| 1055 | */ |
| 1056 | |
| 1057 | inb_next: |
| 1058 | mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ |
| 1059 | inb_next_wait: |
| 1060 | /* |
| 1061 | * If there is a parity error, wait for the kernel to |
| 1062 | * see the interrupt and prepare our message response |
| 1063 | * before continuing. |
| 1064 | */ |
| 1065 | test SSTAT1, REQINIT jz inb_next_wait; |
| 1066 | test SSTAT1, SCSIPERR jnz .; |
| 1067 | and LASTPHASE, PHASE_MASK, SCSISIGI; |
| 1068 | cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; |
| 1069 | inb_first: |
| 1070 | mov DINDEX,SINDEX; |
| 1071 | mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ |
| 1072 | inb_last: |
| 1073 | mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ |
| 1074 | |
| 1075 | |
| 1076 | mesgin_phasemis: |
| 1077 | /* |
| 1078 | * We expected to receive another byte, but the target changed phase |
| 1079 | */ |
| 1080 | mvi INTSTAT, MSGIN_PHASEMIS; |
| 1081 | jmp ITloop; |
| 1082 | |
| 1083 | /* |
| 1084 | * DMA data transfer. HADDR and HCNT must be loaded first, and |
| 1085 | * SINDEX should contain the value to load DFCNTRL with - 0x3d for |
| 1086 | * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared |
| 1087 | * during initialization. |
| 1088 | */ |
| 1089 | if ((p->features & AHC_ULTRA2) == 0) { |
| 1090 | dma: |
| 1091 | mov DFCNTRL,SINDEX; |
| 1092 | dma_loop: |
| 1093 | test SSTAT0,DMADONE jnz dma_dmadone; |
| 1094 | test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ |
| 1095 | dma_phasemis: |
| 1096 | test SSTAT0,SDONE jnz dma_checkfifo; |
| 1097 | mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ |
| 1098 | |
| 1099 | /* |
| 1100 | * We will be "done" DMAing when the transfer count goes to zero, or |
| 1101 | * the target changes the phase (in light of this, it makes sense that |
| 1102 | * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are |
| 1103 | * doing a SCSI->Host transfer, the data FIFO should be flushed auto- |
| 1104 | * magically on STCNT=0 or a phase change, so just wait for FIFO empty |
| 1105 | * status. |
| 1106 | */ |
| 1107 | dma_checkfifo: |
| 1108 | test DFCNTRL,DIRECTION jnz dma_fifoempty; |
| 1109 | dma_fifoflush: |
| 1110 | test DFSTATUS,FIFOEMP jz dma_fifoflush; |
| 1111 | |
| 1112 | dma_fifoempty: |
| 1113 | /* Don't clobber an inprogress host data transfer */ |
| 1114 | test DFSTATUS, MREQPEND jnz dma_fifoempty; |
| 1115 | /* |
| 1116 | * Now shut the DMA enables off and make sure that the DMA enables are |
| 1117 | * actually off first lest we get an ILLSADDR. |
| 1118 | */ |
| 1119 | dma_dmadone: |
| 1120 | cmp LASTPHASE, P_COMMAND je dma_await_nreq; |
| 1121 | test SCSIRATE, 0x0f jnz dma_shutdown; |
| 1122 | dma_await_nreq: |
| 1123 | test SCSISIGI, REQI jz dma_shutdown; |
| 1124 | test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; |
| 1125 | dma_shutdown: |
| 1126 | and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); |
| 1127 | dma_halt: |
| 1128 | /* |
| 1129 | * Some revisions of the aic7880 have a problem where, if the |
| 1130 | * data fifo is full, but the PCI input latch is not empty, |
| 1131 | * HDMAEN cannot be cleared. The fix used here is to attempt |
| 1132 | * to drain the data fifo until there is space for the input |
| 1133 | * latch to drain and HDMAEN de-asserts. |
| 1134 | */ |
| 1135 | if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { |
| 1136 | mov NONE, DFDAT; |
| 1137 | } |
| 1138 | test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; |
| 1139 | } |
| 1140 | return: |
| 1141 | ret; |
| 1142 | |
| 1143 | /* |
| 1144 | * Assert that if we've been reselected, then we've seen an IDENTIFY |
| 1145 | * message. |
| 1146 | */ |
| 1147 | assert: |
| 1148 | test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ |
| 1149 | |
| 1150 | mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ |
| 1151 | |
| 1152 | /* |
| 1153 | * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) |
| 1154 | * or by the SCBID ARG_1. The search begins at the SCB index passed in |
| 1155 | * via SINDEX which is an SCB that must be on the disconnected list. If |
| 1156 | * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR |
| 1157 | * is set to the proper SCB. |
| 1158 | */ |
| 1159 | findSCB: |
| 1160 | mov SCBPTR,SINDEX; /* Initialize SCBPTR */ |
| 1161 | cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; |
| 1162 | mov A, SAVED_TCL; |
| 1163 | mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ |
| 1164 | findSCB_by_SCBID: |
| 1165 | mov A, ARG_1; /* Tag passed in ARG_1 */ |
| 1166 | mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ |
| 1167 | findSCB_next: |
| 1168 | mov ARG_2, SCBPTR; |
| 1169 | cmp SCB_NEXT, SCB_LIST_NULL je notFound; |
| 1170 | mov SCBPTR,SCB_NEXT; |
| 1171 | dec SINDEX; /* Last comparison moved us too far */ |
| 1172 | findSCB_loop: |
| 1173 | cmp SINDIR, A jne findSCB_next; |
| 1174 | mov SINDEX, SCBPTR ret; |
| 1175 | notFound: |
| 1176 | mvi SINDEX, SCB_LIST_NULL ret; |
| 1177 | |
| 1178 | /* |
| 1179 | * Retrieve an SCB by SCBID first searching the disconnected list falling |
| 1180 | * back to DMA'ing the SCB down from the host. This routine assumes that |
| 1181 | * ARG_1 is the SCBID of interrest and that SINDEX is the position in the |
| 1182 | * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, |
| 1183 | * we go directly to the host for the SCB. |
| 1184 | */ |
| 1185 | retrieveSCB: |
| 1186 | test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; |
| 1187 | mov SCBPTR call findSCB; /* Continue the search */ |
| 1188 | cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; |
| 1189 | |
| 1190 | /* |
| 1191 | * This routine expects SINDEX to contain the index of the SCB to be |
| 1192 | * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the |
| 1193 | * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL |
| 1194 | * if it is at the head. |
| 1195 | */ |
| 1196 | rem_scb_from_disc_list: |
| 1197 | /* Remove this SCB from the disconnection list */ |
| 1198 | cmp ARG_2, SCB_LIST_NULL je rHead; |
| 1199 | mov DINDEX, SCB_NEXT; |
| 1200 | mov SCBPTR, ARG_2; |
| 1201 | mov SCB_NEXT, DINDEX; |
| 1202 | mov SCBPTR, SINDEX ret; |
| 1203 | rHead: |
| 1204 | mov DISCONNECTED_SCBH,SCB_NEXT ret; |
| 1205 | |
| 1206 | retrieve_from_host: |
| 1207 | /* |
| 1208 | * We didn't find it. Pull an SCB and DMA down the one we want. |
| 1209 | * We should never get here in the non-paging case. |
| 1210 | */ |
| 1211 | mov ALLZEROS call get_free_or_disc_scb; |
| 1212 | mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; |
| 1213 | /* Jump instead of call as we want to return anyway */ |
| 1214 | mov ARG_1 jmp dma_scb; |
| 1215 | |
| 1216 | /* |
| 1217 | * Determine whether a target is using tagged or non-tagged transactions |
| 1218 | * by first looking for a matching transaction based on the TCL and if |
| 1219 | * that fails, looking up this device in the host's untagged SCB array. |
| 1220 | * The TCL to search for is assumed to be in SAVED_TCL. The value is |
| 1221 | * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). |
| 1222 | * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information |
| 1223 | * in an SCB instead of having to go to the host. |
| 1224 | */ |
| 1225 | get_untagged_SCBID: |
| 1226 | cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; |
| 1227 | mvi ARG_1, SCB_LIST_NULL; |
| 1228 | mov DISCONNECTED_SCBH call findSCB; |
| 1229 | cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; |
| 1230 | or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ |
| 1231 | test SCB_CONTROL, TAG_ENB jnz . + 2; |
| 1232 | mov ARG_1, SCB_TAG ret; |
| 1233 | mvi ARG_1, SCB_LIST_NULL ret; |
| 1234 | |
| 1235 | /* |
| 1236 | * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) |
| 1237 | * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. |
| 1238 | */ |
| 1239 | fetch_byte: |
| 1240 | mov ARG_2, SINDEX; |
| 1241 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 1242 | mvi DINDEX, CCHADDR; |
| 1243 | mvi SCBID_ADDR call set_1byte_addr; |
| 1244 | mvi CCHCNT, 1; |
| 1245 | mvi CCSGCTL, CCSGEN|CCSGRESET; |
| 1246 | test CCSGCTL, CCSGDONE jz .; |
| 1247 | mvi CCSGCTL, CCSGRESET; |
| 1248 | bmov RETURN_2, CCSGRAM, 1 ret; |
| 1249 | } else { |
| 1250 | mvi DINDEX, HADDR; |
| 1251 | mvi SCBID_ADDR call set_1byte_addr; |
| 1252 | mvi HCNT[0], 1; |
| 1253 | clr HCNT[1]; |
| 1254 | clr HCNT[2]; |
| 1255 | mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; |
| 1256 | call dma_finish; |
| 1257 | mov RETURN_2, DFDAT ret; |
| 1258 | } |
| 1259 | |
| 1260 | /* |
| 1261 | * Prepare the hardware to post a byte to host memory given an |
| 1262 | * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. |
| 1263 | */ |
| 1264 | post_byte_setup: |
| 1265 | mov ARG_2, SINDEX; |
| 1266 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 1267 | mvi DINDEX, CCHADDR; |
| 1268 | mvi SCBID_ADDR call set_1byte_addr; |
| 1269 | mvi CCHCNT, 1; |
| 1270 | mvi CCSCBCTL, CCSCBRESET ret; |
| 1271 | } else { |
| 1272 | mvi DINDEX, HADDR; |
| 1273 | mvi SCBID_ADDR call set_1byte_addr; |
| 1274 | mvi HCNT[0], 1; |
| 1275 | clr HCNT[1]; |
| 1276 | clr HCNT[2]; |
| 1277 | mvi DFCNTRL, FIFORESET ret; |
| 1278 | } |
| 1279 | |
| 1280 | post_byte: |
| 1281 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 1282 | bmov CCSCBRAM, SINDEX, 1; |
| 1283 | or CCSCBCTL, CCSCBEN|CCSCBRESET; |
| 1284 | test CCSCBCTL, CCSCBDONE jz .; |
| 1285 | clr CCSCBCTL ret; |
| 1286 | } else { |
| 1287 | mov DFDAT, SINDEX; |
| 1288 | or DFCNTRL, HDMAEN|FIFOFLUSH; |
| 1289 | jmp dma_finish; |
| 1290 | } |
| 1291 | |
| 1292 | get_SCBID_from_host: |
| 1293 | mov A, SAVED_TCL; |
| 1294 | mvi UNTAGGEDSCB_OFFSET call fetch_byte; |
| 1295 | mov RETURN_1, RETURN_2 ret; |
| 1296 | |
| 1297 | phase_lock: |
| 1298 | test SSTAT1, REQINIT jz phase_lock; |
| 1299 | test SSTAT1, SCSIPERR jnz phase_lock; |
| 1300 | and SCSISIGO, PHASE_MASK, SCSISIGI; |
| 1301 | and LASTPHASE, PHASE_MASK, SCSISIGI ret; |
| 1302 | |
| 1303 | if ((p->features & AHC_CMD_CHAN) == 0) { |
| 1304 | set_stcnt_from_hcnt: |
| 1305 | mov STCNT[0], HCNT[0]; |
| 1306 | mov STCNT[1], HCNT[1]; |
| 1307 | mov STCNT[2], HCNT[2] ret; |
| 1308 | |
| 1309 | bcopy_7: |
| 1310 | mov DINDIR, SINDIR; |
| 1311 | mov DINDIR, SINDIR; |
| 1312 | bcopy_5: |
| 1313 | mov DINDIR, SINDIR; |
| 1314 | bcopy_4: |
| 1315 | mov DINDIR, SINDIR; |
| 1316 | bcopy_3: |
| 1317 | mov DINDIR, SINDIR; |
| 1318 | mov DINDIR, SINDIR; |
| 1319 | mov DINDIR, SINDIR ret; |
| 1320 | } |
| 1321 | |
| 1322 | /* |
| 1323 | * Setup addr assuming that A is an index into |
| 1324 | * an array of 32byte objects, SINDEX contains |
| 1325 | * the base address of that array, and DINDEX |
| 1326 | * contains the base address of the location |
| 1327 | * to store the indexed address. |
| 1328 | */ |
| 1329 | set_32byte_addr: |
| 1330 | shr ARG_2, 3, A; |
| 1331 | shl A, 5; |
| 1332 | /* |
| 1333 | * Setup addr assuming that A + (ARG_1 * 256) is an |
| 1334 | * index into an array of 1byte objects, SINDEX contains |
| 1335 | * the base address of that array, and DINDEX contains |
| 1336 | * the base address of the location to store the computed |
| 1337 | * address. |
| 1338 | */ |
| 1339 | set_1byte_addr: |
| 1340 | add DINDIR, A, SINDIR; |
| 1341 | mov A, ARG_2; |
| 1342 | adc DINDIR, A, SINDIR; |
| 1343 | clr A; |
| 1344 | adc DINDIR, A, SINDIR; |
| 1345 | adc DINDIR, A, SINDIR ret; |
| 1346 | |
| 1347 | /* |
| 1348 | * Either post or fetch and SCB from host memory based on the |
| 1349 | * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. |
| 1350 | */ |
| 1351 | dma_scb: |
| 1352 | mov A, SINDEX; |
| 1353 | if ((p->features & AHC_CMD_CHAN) != 0) { |
| 1354 | mvi DINDEX, CCHADDR; |
| 1355 | mvi HSCB_ADDR call set_32byte_addr; |
| 1356 | mov CCSCBPTR, SCBPTR; |
| 1357 | mvi CCHCNT, 32; |
| 1358 | test DMAPARAMS, DIRECTION jz dma_scb_tohost; |
| 1359 | mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; |
| 1360 | cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; |
| 1361 | jmp dma_scb_finish; |
| 1362 | dma_scb_tohost: |
| 1363 | if ((p->features & AHC_ULTRA2) == 0) { |
| 1364 | mvi CCSCBCTL, CCSCBRESET; |
| 1365 | bmov CCSCBRAM, SCB_CONTROL, 32; |
| 1366 | or CCSCBCTL, CCSCBEN|CCSCBRESET; |
| 1367 | test CCSCBCTL, CCSCBDONE jz .; |
| 1368 | } |
| 1369 | if ((p->features & AHC_ULTRA2) != 0) { |
| 1370 | if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { |
| 1371 | mvi CCSCBCTL, CCARREN|CCSCBRESET; |
| 1372 | cmp CCSCBCTL, ARRDONE|CCARREN jne .; |
| 1373 | mvi CCHCNT, 32; |
| 1374 | mvi CCSCBCTL, CCSCBEN|CCSCBRESET; |
| 1375 | cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; |
| 1376 | } else { |
| 1377 | mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; |
| 1378 | cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; |
| 1379 | } |
| 1380 | } |
| 1381 | dma_scb_finish: |
| 1382 | clr CCSCBCTL; |
| 1383 | test CCSCBCTL, CCARREN|CCSCBEN jnz .; |
| 1384 | ret; |
| 1385 | } |
| 1386 | if ((p->features & AHC_CMD_CHAN) == 0) { |
| 1387 | mvi DINDEX, HADDR; |
| 1388 | mvi HSCB_ADDR call set_32byte_addr; |
| 1389 | mvi HCNT[0], 32; |
| 1390 | clr HCNT[1]; |
| 1391 | clr HCNT[2]; |
| 1392 | mov DFCNTRL, DMAPARAMS; |
| 1393 | test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; |
| 1394 | /* Fill it with the SCB data */ |
| 1395 | copy_scb_tofifo: |
| 1396 | mvi SINDEX, SCB_CONTROL; |
| 1397 | add A, 32, SINDEX; |
| 1398 | copy_scb_tofifo_loop: |
| 1399 | mov DFDAT,SINDIR; |
| 1400 | mov DFDAT,SINDIR; |
| 1401 | mov DFDAT,SINDIR; |
| 1402 | mov DFDAT,SINDIR; |
| 1403 | mov DFDAT,SINDIR; |
| 1404 | mov DFDAT,SINDIR; |
| 1405 | mov DFDAT,SINDIR; |
| 1406 | mov DFDAT,SINDIR; |
| 1407 | cmp SINDEX, A jne copy_scb_tofifo_loop; |
| 1408 | or DFCNTRL, HDMAEN|FIFOFLUSH; |
| 1409 | jmp dma_finish; |
| 1410 | dma_scb_fromhost: |
| 1411 | mvi DINDEX, SCB_CONTROL; |
| 1412 | if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { |
| 1413 | /* |
| 1414 | * Set the A to -24. It it hits 0, then we let |
| 1415 | * our code fall through to dfdat_in_8 to complete |
| 1416 | * the last of the copy. |
| 1417 | * |
| 1418 | * Also, things happen 8 bytes at a time in this |
| 1419 | * case, so we may need to drain the fifo at most |
| 1420 | * 3 times to keep things flowing |
| 1421 | */ |
| 1422 | mvi A, -24; |
| 1423 | dma_scb_hang_fifo: |
| 1424 | /* Wait for the first bit of data to hit the fifo */ |
| 1425 | test DFSTATUS, FIFOEMP jnz .; |
| 1426 | dma_scb_hang_wait: |
| 1427 | /* OK, now they've started to transfer into the fifo, |
| 1428 | * so wait for them to stop trying to transfer any |
| 1429 | * more data. |
| 1430 | */ |
| 1431 | test DFSTATUS, MREQPEND jnz .; |
| 1432 | /* |
| 1433 | * OK, they started, then they stopped, now see if they |
| 1434 | * managed to complete the job before stopping. Try |
| 1435 | * it multiple times to give the chip a few cycles to |
| 1436 | * set the flag if it did complete. |
| 1437 | */ |
| 1438 | test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; |
| 1439 | test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; |
| 1440 | test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; |
| 1441 | /* |
| 1442 | * Too bad, the chip didn't complete the DMA, but there |
| 1443 | * aren't any more memory requests pending, so that |
| 1444 | * means it stopped part way through and hung. That's |
| 1445 | * our bug, so now we drain what data there is in the |
| 1446 | * fifo in order to get things going again. |
| 1447 | */ |
| 1448 | dma_scb_hang_empty_fifo: |
| 1449 | call dfdat_in_8; |
| 1450 | add A, 8; |
| 1451 | add SINDEX, A, HCNT; |
| 1452 | /* |
| 1453 | * If there are another 8 bytes of data waiting in the |
| 1454 | * fifo, then the carry bit will be set as a result |
| 1455 | * of the above add command (unless A is non-negative, |
| 1456 | * in which case the carry bit won't be set). |
| 1457 | */ |
| 1458 | jc dma_scb_hang_empty_fifo; |
| 1459 | /* |
| 1460 | * We've emptied the fifo now, but we wouldn't have got |
| 1461 | * here if the memory transfer hadn't stopped part way |
| 1462 | * through, so go back up to the beginning of the |
| 1463 | * loop and start over. When it succeeds in getting |
| 1464 | * all the data down, HDONE will be set and we'll |
| 1465 | * jump to the code just below here. |
| 1466 | */ |
| 1467 | jmp dma_scb_hang_fifo; |
| 1468 | dma_scb_hang_dma_done: |
| 1469 | and DFCNTRL, ~HDMAEN; |
| 1470 | test DFCNTRL, HDMAEN jnz .; |
| 1471 | call dfdat_in_8; |
| 1472 | add A, 8; |
| 1473 | cmp A, 8 jne . - 2; |
| 1474 | ret; |
| 1475 | } else { |
| 1476 | call dma_finish; |
| 1477 | call dfdat_in_8; |
| 1478 | call dfdat_in_8; |
| 1479 | call dfdat_in_8; |
| 1480 | } |
| 1481 | dfdat_in_8: |
| 1482 | mov DINDIR,DFDAT; |
| 1483 | dfdat_in_7: |
| 1484 | mov DINDIR,DFDAT; |
| 1485 | mov DINDIR,DFDAT; |
| 1486 | mov DINDIR,DFDAT; |
| 1487 | mov DINDIR,DFDAT; |
| 1488 | mov DINDIR,DFDAT; |
| 1489 | mov DINDIR,DFDAT; |
| 1490 | mov DINDIR,DFDAT ret; |
| 1491 | } |
| 1492 | |
| 1493 | |
| 1494 | /* |
| 1495 | * Wait for DMA from host memory to data FIFO to complete, then disable |
| 1496 | * DMA and wait for it to acknowledge that it's off. |
| 1497 | */ |
| 1498 | if ((p->features & AHC_CMD_CHAN) == 0) { |
| 1499 | dma_finish: |
| 1500 | test DFSTATUS,HDONE jz dma_finish; |
| 1501 | /* Turn off DMA */ |
| 1502 | and DFCNTRL, ~HDMAEN; |
| 1503 | test DFCNTRL, HDMAEN jnz .; |
| 1504 | ret; |
| 1505 | } |
| 1506 | |
| 1507 | add_scb_to_free_list: |
| 1508 | if ((p->flags & AHC_PAGESCBS) != 0) { |
| 1509 | mov SCB_NEXT, FREE_SCBH; |
| 1510 | mov FREE_SCBH, SCBPTR; |
| 1511 | } |
| 1512 | mvi SCB_TAG, SCB_LIST_NULL ret; |
| 1513 | |
| 1514 | if ((p->flags & AHC_PAGESCBS) != 0) { |
| 1515 | get_free_or_disc_scb: |
| 1516 | cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; |
| 1517 | cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; |
| 1518 | return_error: |
| 1519 | mvi SINDEX, SCB_LIST_NULL ret; |
| 1520 | dequeue_disc_scb: |
| 1521 | mov SCBPTR, DISCONNECTED_SCBH; |
| 1522 | dma_up_scb: |
| 1523 | mvi DMAPARAMS, FIFORESET; |
| 1524 | mov SCB_TAG call dma_scb; |
| 1525 | unlink_disc_scb: |
| 1526 | mov DISCONNECTED_SCBH, SCB_NEXT ret; |
| 1527 | dequeue_free_scb: |
| 1528 | mov SCBPTR, FREE_SCBH; |
| 1529 | mov FREE_SCBH, SCB_NEXT ret; |
| 1530 | } |
| 1531 | |
| 1532 | add_scb_to_disc_list: |
| 1533 | /* |
| 1534 | * Link this SCB into the DISCONNECTED list. This list holds the |
| 1535 | * candidates for paging out an SCB if one is needed for a new command. |
| 1536 | * Modifying the disconnected list is a critical(pause dissabled) section. |
| 1537 | */ |
| 1538 | mov SCB_NEXT, DISCONNECTED_SCBH; |
| 1539 | mov DISCONNECTED_SCBH, SCBPTR ret; |