18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 1994-2001 Justin T. Gibbs. 58c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001 Adaptec Inc. 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 108c2ecf20Sopenharmony_ci * are met: 118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 128c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 138c2ecf20Sopenharmony_ci * without modification. 148c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer 158c2ecf20Sopenharmony_ci * substantially similar to the "NO WARRANTY" disclaimer below 168c2ecf20Sopenharmony_ci * ("Disclaimer") and any redistribution must be conditioned upon 178c2ecf20Sopenharmony_ci * including a substantially similar Disclaimer requirement for further 188c2ecf20Sopenharmony_ci * binary redistribution. 198c2ecf20Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names 208c2ecf20Sopenharmony_ci * of any contributors may be used to endorse or promote products derived 218c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 248c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 258c2ecf20Sopenharmony_ci * Software Foundation. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * NO WARRANTY 288c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 298c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 308c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 318c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328c2ecf20Sopenharmony_ci * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 338c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 348c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 358c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 368c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 378c2ecf20Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 388c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGES. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * $FreeBSD$ 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciVERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" 448c2ecf20Sopenharmony_ciPATCH_ARG_LIST = "struct ahc_softc *ahc" 458c2ecf20Sopenharmony_ciPREFIX = "ahc_" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "aic7xxx.reg" 488c2ecf20Sopenharmony_ci#include "scsi_message.h" 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * A few words on the waiting SCB list: 528c2ecf20Sopenharmony_ci * After starting the selection hardware, we check for reconnecting targets 538c2ecf20Sopenharmony_ci * as well as for our selection to complete just in case the reselection wins 548c2ecf20Sopenharmony_ci * bus arbitration. The problem with this is that we must keep track of the 558c2ecf20Sopenharmony_ci * SCB that we've already pulled from the QINFIFO and started the selection 568c2ecf20Sopenharmony_ci * on just in case the reselection wins so that we can retry the selection at 578c2ecf20Sopenharmony_ci * a later time. This problem cannot be resolved by holding a single entry 588c2ecf20Sopenharmony_ci * in scratch ram since a reconnecting target can request sense and this will 598c2ecf20Sopenharmony_ci * create yet another SCB waiting for selection. The solution used here is to 608c2ecf20Sopenharmony_ci * use byte 27 of the SCB as a pseudo-next pointer and to thread a list 618c2ecf20Sopenharmony_ci * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, 628c2ecf20Sopenharmony_ci * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to 638c2ecf20Sopenharmony_ci * this list every time a request sense occurs or after completing a non-tagged 648c2ecf20Sopenharmony_ci * command for which a second SCB has been queued. The sequencer will 658c2ecf20Sopenharmony_ci * automatically consume the entries. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cibus_free_sel: 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * Turn off the selection hardware. We need to reset the 718c2ecf20Sopenharmony_ci * selection request in order to perform a new selection. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; 748c2ecf20Sopenharmony_ci and SIMODE1, ~ENBUSFREE; 758c2ecf20Sopenharmony_cipoll_for_work: 768c2ecf20Sopenharmony_ci call clear_target_state; 778c2ecf20Sopenharmony_ci and SXFRCTL0, ~SPIOEN; 788c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 798c2ecf20Sopenharmony_ci clr SCSIBUSL; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci test SCSISEQ, ENSELO jnz poll_for_selection; 828c2ecf20Sopenharmony_ci if ((ahc->features & AHC_TWIN) != 0) { 838c2ecf20Sopenharmony_ci xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 848c2ecf20Sopenharmony_ci test SCSISEQ, ENSELO jnz poll_for_selection; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; 878c2ecf20Sopenharmony_cipoll_for_work_loop: 888c2ecf20Sopenharmony_ci if ((ahc->features & AHC_TWIN) != 0) { 898c2ecf20Sopenharmony_ci xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci test SSTAT0, SELDO|SELDI jnz selection; 928c2ecf20Sopenharmony_citest_queue: 938c2ecf20Sopenharmony_ci /* Has the driver posted any work for us? */ 948c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 958c2ecf20Sopenharmony_ci if ((ahc->features & AHC_QUEUE_REGS) != 0) { 968c2ecf20Sopenharmony_ci test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci mov A, QINPOS; 998c2ecf20Sopenharmony_ci cmp KERNEL_QINPOS, A je poll_for_work_loop; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci mov ARG_1, NEXT_QUEUED_SCB; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * We have at least one queued SCB now and we don't have any 1058c2ecf20Sopenharmony_ci * SCBs in the list of SCBs awaiting selection. Allocate a 1068c2ecf20Sopenharmony_ci * card SCB for the host's SCB and get to work on it. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 1098c2ecf20Sopenharmony_ci mov ALLZEROS call get_free_or_disc_scb; 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci /* In the non-paging case, the SCBID == hardware SCB index */ 1128c2ecf20Sopenharmony_ci mov SCBPTR, ARG_1; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci or SEQ_FLAGS2, SCB_DMA; 1158c2ecf20Sopenharmony_ciEND_CRITICAL; 1168c2ecf20Sopenharmony_cidma_queued_scb: 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * DMA the SCB from host ram into the current SCB location. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 1218c2ecf20Sopenharmony_ci mov ARG_1 call dma_scb; 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Check one last time to see if this SCB was canceled 1248c2ecf20Sopenharmony_ci * before we completed the DMA operation. If it was, 1258c2ecf20Sopenharmony_ci * the QINFIFO next pointer will not match our saved 1268c2ecf20Sopenharmony_ci * value. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci mov A, ARG_1; 1298c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 1308c2ecf20Sopenharmony_ci cmp NEXT_QUEUED_SCB, A jne abort_qinscb; 1318c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 1328c2ecf20Sopenharmony_ci cmp SCB_TAG, A je . + 2; 1338c2ecf20Sopenharmony_ci mvi SCB_MISMATCH call set_seqint; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci mov NEXT_QUEUED_SCB, SCB_NEXT; 1368c2ecf20Sopenharmony_ci mov SCB_NEXT,WAITING_SCBH; 1378c2ecf20Sopenharmony_ci mov WAITING_SCBH, SCBPTR; 1388c2ecf20Sopenharmony_ci if ((ahc->features & AHC_QUEUE_REGS) != 0) { 1398c2ecf20Sopenharmony_ci mov NONE, SNSCB_QOFF; 1408c2ecf20Sopenharmony_ci } else { 1418c2ecf20Sopenharmony_ci inc QINPOS; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci and SEQ_FLAGS2, ~SCB_DMA; 1448c2ecf20Sopenharmony_ciEND_CRITICAL; 1458c2ecf20Sopenharmony_cistart_waiting: 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * Start the first entry on the waiting SCB list. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci mov SCBPTR, WAITING_SCBH; 1508c2ecf20Sopenharmony_ci call start_selection; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cipoll_for_selection: 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * Twin channel devices cannot handle things like SELTO 1558c2ecf20Sopenharmony_ci * interrupts on the "background" channel. So, while 1568c2ecf20Sopenharmony_ci * selecting, keep polling the current channel until 1578c2ecf20Sopenharmony_ci * either a selection or reselection occurs. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci test SSTAT0, SELDO|SELDI jz poll_for_selection; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciselection: 1628c2ecf20Sopenharmony_ci /* 1638c2ecf20Sopenharmony_ci * We aren't expecting a bus free, so interrupt 1648c2ecf20Sopenharmony_ci * the kernel driver if it happens. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci mvi CLRSINT1,CLRBUSFREE; 1678c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 1688c2ecf20Sopenharmony_ci or SIMODE1, ENBUSFREE; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * Guard against a bus free after (re)selection 1738c2ecf20Sopenharmony_ci * but prior to enabling the busfree interrupt. SELDI 1748c2ecf20Sopenharmony_ci * and SELDO will be cleared in that case. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci test SSTAT0, SELDI|SELDO jz bus_free_sel; 1778c2ecf20Sopenharmony_ci test SSTAT0,SELDO jnz select_out; 1788c2ecf20Sopenharmony_ciselect_in: 1798c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 1808c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_INITIATORROLE) != 0) { 1818c2ecf20Sopenharmony_ci test SSTAT0, TARGET jz initiator_reselect; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci mvi CLRSINT0, CLRSELDI; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * We've just been selected. Assert BSY and 1878c2ecf20Sopenharmony_ci * setup the phase for receiving messages 1888c2ecf20Sopenharmony_ci * from the target. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci mvi SCSISIGO, P_MESGOUT|BSYO; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Setup the DMA for sending the identify and 1948c2ecf20Sopenharmony_ci * command information. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci mvi SEQ_FLAGS, CMDPHASE_PENDING; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci mov A, TQINPOS; 1998c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 2008c2ecf20Sopenharmony_ci mvi DINDEX, CCHADDR; 2018c2ecf20Sopenharmony_ci mvi SHARED_DATA_ADDR call set_32byte_addr; 2028c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCSCBRESET; 2038c2ecf20Sopenharmony_ci } else { 2048c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 2058c2ecf20Sopenharmony_ci mvi SHARED_DATA_ADDR call set_32byte_addr; 2068c2ecf20Sopenharmony_ci mvi DFCNTRL, FIFORESET; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Initiator that selected us */ 2108c2ecf20Sopenharmony_ci and SAVED_SCSIID, SELID_MASK, SELID; 2118c2ecf20Sopenharmony_ci /* The Target ID we were selected at */ 2128c2ecf20Sopenharmony_ci if ((ahc->features & AHC_MULTI_TID) != 0) { 2138c2ecf20Sopenharmony_ci and A, OID, TARGIDIN; 2148c2ecf20Sopenharmony_ci } else if ((ahc->features & AHC_ULTRA2) != 0) { 2158c2ecf20Sopenharmony_ci and A, OID, SCSIID_ULTRA2; 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci and A, OID, SCSIID; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci or SAVED_SCSIID, A; 2208c2ecf20Sopenharmony_ci if ((ahc->features & AHC_TWIN) != 0) { 2218c2ecf20Sopenharmony_ci test SBLKCTL, SELBUSB jz . + 2; 2228c2ecf20Sopenharmony_ci or SAVED_SCSIID, TWIN_CHNLB; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 2258c2ecf20Sopenharmony_ci mov CCSCBRAM, SAVED_SCSIID; 2268c2ecf20Sopenharmony_ci } else { 2278c2ecf20Sopenharmony_ci mov DFDAT, SAVED_SCSIID; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * If ATN isn't asserted, the target isn't interested 2328c2ecf20Sopenharmony_ci * in talking to us. Go directly to bus free. 2338c2ecf20Sopenharmony_ci * XXX SCSI-1 may require us to assume lun 0 if 2348c2ecf20Sopenharmony_ci * ATN is false. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jz target_busfree; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * Watch ATN closely now as we pull in messages from the 2408c2ecf20Sopenharmony_ci * initiator. We follow the guidlines from section 6.5 2418c2ecf20Sopenharmony_ci * of the SCSI-2 spec for what messages are allowed when. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci call target_inb; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * Our first message must be one of IDENTIFY, ABORT, or 2478c2ecf20Sopenharmony_ci * BUS_DEVICE_RESET. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; 2508c2ecf20Sopenharmony_ci /* Store for host */ 2518c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 2528c2ecf20Sopenharmony_ci mov CCSCBRAM, DINDEX; 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci mov DFDAT, DINDEX; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci and SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Remember for disconnection decision */ 2598c2ecf20Sopenharmony_ci test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; 2608c2ecf20Sopenharmony_ci /* XXX Honor per target settings too */ 2618c2ecf20Sopenharmony_ci or SEQ_FLAGS, NO_DISCONNECT; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jz ident_messages_done; 2648c2ecf20Sopenharmony_ci call target_inb; 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * If this is a tagged request, the tagged message must 2678c2ecf20Sopenharmony_ci * immediately follow the identify. We test for a valid 2688c2ecf20Sopenharmony_ci * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and 2698c2ecf20Sopenharmony_ci * < MSG_IGN_WIDE_RESIDUE. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci add A, -MSG_SIMPLE_Q_TAG, DINDEX; 2728c2ecf20Sopenharmony_ci jnc ident_messages_done_msg_pending; 2738c2ecf20Sopenharmony_ci add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; 2748c2ecf20Sopenharmony_ci jc ident_messages_done_msg_pending; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Store for host */ 2778c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 2788c2ecf20Sopenharmony_ci mov CCSCBRAM, DINDEX; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci mov DFDAT, DINDEX; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * If the initiator doesn't feel like providing a tag number, 2858c2ecf20Sopenharmony_ci * we've got a failed selection and must transition to bus 2868c2ecf20Sopenharmony_ci * free. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jz target_busfree; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Store the tag for the host. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci call target_inb; 2948c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 2958c2ecf20Sopenharmony_ci mov CCSCBRAM, DINDEX; 2968c2ecf20Sopenharmony_ci } else { 2978c2ecf20Sopenharmony_ci mov DFDAT, DINDEX; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci mov INITIATOR_TAG, DINDEX; 3008c2ecf20Sopenharmony_ci or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ciident_messages_done: 3038c2ecf20Sopenharmony_ci /* Terminate the ident list */ 3048c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 3058c2ecf20Sopenharmony_ci mvi CCSCBRAM, SCB_LIST_NULL; 3068c2ecf20Sopenharmony_ci } else { 3078c2ecf20Sopenharmony_ci mvi DFDAT, SCB_LIST_NULL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci or SEQ_FLAGS, TARG_CMD_PENDING; 3108c2ecf20Sopenharmony_ci test SEQ_FLAGS2, TARGET_MSG_PENDING 3118c2ecf20Sopenharmony_ci jnz target_mesgout_pending; 3128c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jnz target_mesgout_continue; 3138c2ecf20Sopenharmony_ci jmp target_ITloop; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciident_messages_done_msg_pending: 3178c2ecf20Sopenharmony_ci or SEQ_FLAGS2, TARGET_MSG_PENDING; 3188c2ecf20Sopenharmony_ci jmp ident_messages_done; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * Pushed message loop to allow the kernel to 3228c2ecf20Sopenharmony_ci * run it's own target mode message state engine. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cihost_target_message_loop: 3258c2ecf20Sopenharmony_ci mvi HOST_MSG_LOOP call set_seqint; 3268c2ecf20Sopenharmony_ci cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; 3278c2ecf20Sopenharmony_ci test SSTAT0, SPIORDY jz .; 3288c2ecf20Sopenharmony_ci jmp host_target_message_loop; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_INITIATORROLE) != 0) { 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * Reselection has been initiated by a target. Make a note that we've been 3348c2ecf20Sopenharmony_ci * reselected, but haven't seen an IDENTIFY message from the target yet. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ciinitiator_reselect: 3378c2ecf20Sopenharmony_ci /* XXX test for and handle ONE BIT condition */ 3388c2ecf20Sopenharmony_ci or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 3398c2ecf20Sopenharmony_ci and SAVED_SCSIID, SELID_MASK, SELID; 3408c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 3418c2ecf20Sopenharmony_ci and A, OID, SCSIID_ULTRA2; 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci and A, OID, SCSIID; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci or SAVED_SCSIID, A; 3468c2ecf20Sopenharmony_ci if ((ahc->features & AHC_TWIN) != 0) { 3478c2ecf20Sopenharmony_ci test SBLKCTL, SELBUSB jz . + 2; 3488c2ecf20Sopenharmony_ci or SAVED_SCSIID, TWIN_CHNLB; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci mvi CLRSINT0, CLRSELDI; 3518c2ecf20Sopenharmony_ci jmp ITloop; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciabort_qinscb: 3558c2ecf20Sopenharmony_ci call add_scb_to_free_list; 3568c2ecf20Sopenharmony_ci jmp poll_for_work_loop; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistart_selection: 3598c2ecf20Sopenharmony_ci /* 3608c2ecf20Sopenharmony_ci * If bus reset interrupts have been disabled (from a previous 3618c2ecf20Sopenharmony_ci * reset), re-enable them now. Resets are only of interest 3628c2ecf20Sopenharmony_ci * when we have outstanding transactions, so we can safely 3638c2ecf20Sopenharmony_ci * defer re-enabling the interrupt until, as an initiator, 3648c2ecf20Sopenharmony_ci * we start sending out transactions again. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci test SIMODE1, ENSCSIRST jnz . + 3; 3678c2ecf20Sopenharmony_ci mvi CLRSINT1, CLRSCSIRSTI; 3688c2ecf20Sopenharmony_ci or SIMODE1, ENSCSIRST; 3698c2ecf20Sopenharmony_ci if ((ahc->features & AHC_TWIN) != 0) { 3708c2ecf20Sopenharmony_ci and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ 3718c2ecf20Sopenharmony_ci test SCB_SCSIID, TWIN_CHNLB jz . + 2; 3728c2ecf20Sopenharmony_ci or SINDEX, SELBUSB; 3738c2ecf20Sopenharmony_ci mov SBLKCTL,SINDEX; /* select channel */ 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ciinitialize_scsiid: 3768c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 3778c2ecf20Sopenharmony_ci mov SCSIID_ULTRA2, SCB_SCSIID; 3788c2ecf20Sopenharmony_ci } else if ((ahc->features & AHC_TWIN) != 0) { 3798c2ecf20Sopenharmony_ci and SCSIID, TWIN_TID|OID, SCB_SCSIID; 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci mov SCSIID, SCB_SCSIID; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 3848c2ecf20Sopenharmony_ci mov SINDEX, SCSISEQ_TEMPLATE; 3858c2ecf20Sopenharmony_ci test SCB_CONTROL, TARGET_SCB jz . + 2; 3868c2ecf20Sopenharmony_ci or SINDEX, TEMODE; 3878c2ecf20Sopenharmony_ci mov SCSISEQ, SINDEX ret; 3888c2ecf20Sopenharmony_ci } else { 3898c2ecf20Sopenharmony_ci mov SCSISEQ, SCSISEQ_TEMPLATE ret; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* 3938c2ecf20Sopenharmony_ci * Initialize transfer settings with SCB provided settings. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ciset_transfer_settings: 3968c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA) != 0) { 3978c2ecf20Sopenharmony_ci test SCB_CONTROL, ULTRAENB jz . + 2; 3988c2ecf20Sopenharmony_ci or SXFRCTL0, FAST20; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * Initialize SCSIRATE with the appropriate value for this target. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 4048c2ecf20Sopenharmony_ci bmov SCSIRATE, SCB_SCSIRATE, 2 ret; 4058c2ecf20Sopenharmony_ci } else { 4068c2ecf20Sopenharmony_ci mov SCSIRATE, SCB_SCSIRATE ret; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_TARGETROLE) != 0) { 4108c2ecf20Sopenharmony_ci/* 4118c2ecf20Sopenharmony_ci * We carefully toggle SPIOEN to allow us to return the 4128c2ecf20Sopenharmony_ci * message byte we receive so it can be checked prior to 4138c2ecf20Sopenharmony_ci * driving REQ on the bus for the next byte. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_citarget_inb: 4168c2ecf20Sopenharmony_ci /* 4178c2ecf20Sopenharmony_ci * Drive REQ on the bus by enabling SCSI PIO. 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci or SXFRCTL0, SPIOEN; 4208c2ecf20Sopenharmony_ci /* Wait for the byte */ 4218c2ecf20Sopenharmony_ci test SSTAT0, SPIORDY jz .; 4228c2ecf20Sopenharmony_ci /* Prevent our read from triggering another REQ */ 4238c2ecf20Sopenharmony_ci and SXFRCTL0, ~SPIOEN; 4248c2ecf20Sopenharmony_ci /* Save latched contents */ 4258c2ecf20Sopenharmony_ci mov DINDEX, SCSIDATL ret; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* 4298c2ecf20Sopenharmony_ci * After the selection, remove this SCB from the "waiting SCB" 4308c2ecf20Sopenharmony_ci * list. This is achieved by simply moving our "next" pointer into 4318c2ecf20Sopenharmony_ci * WAITING_SCBH. Our next pointer will be set to null the next time this 4328c2ecf20Sopenharmony_ci * SCB is used, so don't bother with it now. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_ciselect_out: 4358c2ecf20Sopenharmony_ci /* Turn off the selection hardware */ 4368c2ecf20Sopenharmony_ci and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; 4378c2ecf20Sopenharmony_ci mov SCBPTR, WAITING_SCBH; 4388c2ecf20Sopenharmony_ci mov WAITING_SCBH,SCB_NEXT; 4398c2ecf20Sopenharmony_ci mov SAVED_SCSIID, SCB_SCSIID; 4408c2ecf20Sopenharmony_ci and SAVED_LUN, LID, SCB_LUN; 4418c2ecf20Sopenharmony_ci call set_transfer_settings; 4428c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 4438c2ecf20Sopenharmony_ci test SSTAT0, TARGET jz initiator_select; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* 4488c2ecf20Sopenharmony_ci * Put tag in connonical location since not 4498c2ecf20Sopenharmony_ci * all connections have an SCB. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci mov INITIATOR_TAG, SCB_TARGET_ITAG; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * We've just re-selected an initiator. 4558c2ecf20Sopenharmony_ci * Assert BSY and setup the phase for 4568c2ecf20Sopenharmony_ci * sending our identify messages. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci mvi P_MESGIN|BSYO call change_phase; 4598c2ecf20Sopenharmony_ci mvi CLRSINT0, CLRSELDO; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * Start out with a simple identify message. 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_ci or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * If we are the result of a tagged command, send 4688c2ecf20Sopenharmony_ci * a simple Q tag and the tag id. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci test SCB_CONTROL, TAG_ENB jz . + 3; 4718c2ecf20Sopenharmony_ci mvi MSG_SIMPLE_Q_TAG call target_outb; 4728c2ecf20Sopenharmony_ci mov SCB_TARGET_ITAG call target_outb; 4738c2ecf20Sopenharmony_citarget_synccmd: 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * Now determine what phases the host wants us 4768c2ecf20Sopenharmony_ci * to go through. 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci mov SEQ_FLAGS, SCB_TARGET_PHASES; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci test SCB_CONTROL, MK_MESSAGE jz target_ITloop; 4818c2ecf20Sopenharmony_ci mvi P_MESGIN|BSYO call change_phase; 4828c2ecf20Sopenharmony_ci jmp host_target_message_loop; 4838c2ecf20Sopenharmony_citarget_ITloop: 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * Start honoring ATN signals now that 4868c2ecf20Sopenharmony_ci * we properly identified ourselves. 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jnz target_mesgout; 4898c2ecf20Sopenharmony_ci test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; 4908c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; 4918c2ecf20Sopenharmony_ci test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * No more work to do. Either disconnect or not depending 4958c2ecf20Sopenharmony_ci * on the state of NO_DISCONNECT. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 4988c2ecf20Sopenharmony_ci mvi TARG_IMMEDIATE_SCB, SCB_LIST_NULL; 4998c2ecf20Sopenharmony_ci call complete_target_cmd; 5008c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 5018c2ecf20Sopenharmony_ci mov ALLZEROS call get_free_or_disc_scb; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci cmp TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .; 5048c2ecf20Sopenharmony_ci mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 5058c2ecf20Sopenharmony_ci mov TARG_IMMEDIATE_SCB call dma_scb; 5068c2ecf20Sopenharmony_ci call set_transfer_settings; 5078c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 5088c2ecf20Sopenharmony_ci jmp target_synccmd; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_citarget_mesgout: 5118c2ecf20Sopenharmony_ci mvi SCSISIGO, P_MESGOUT|BSYO; 5128c2ecf20Sopenharmony_citarget_mesgout_continue: 5138c2ecf20Sopenharmony_ci call target_inb; 5148c2ecf20Sopenharmony_citarget_mesgout_pending: 5158c2ecf20Sopenharmony_ci and SEQ_FLAGS2, ~TARGET_MSG_PENDING; 5168c2ecf20Sopenharmony_ci /* Local Processing goes here... */ 5178c2ecf20Sopenharmony_ci jmp host_target_message_loop; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_citarget_disconnect: 5208c2ecf20Sopenharmony_ci mvi P_MESGIN|BSYO call change_phase; 5218c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE jz . + 2; 5228c2ecf20Sopenharmony_ci mvi MSG_SAVEDATAPOINTER call target_outb; 5238c2ecf20Sopenharmony_ci mvi MSG_DISCONNECT call target_outb; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_citarget_busfree_wait: 5268c2ecf20Sopenharmony_ci /* Wait for preceding I/O session to complete. */ 5278c2ecf20Sopenharmony_ci test SCSISIGI, ACKI jnz .; 5288c2ecf20Sopenharmony_citarget_busfree: 5298c2ecf20Sopenharmony_ci and SIMODE1, ~ENBUSFREE; 5308c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 5318c2ecf20Sopenharmony_ci clr SCSIBUSL; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci clr SCSISIGO; 5348c2ecf20Sopenharmony_ci mvi LASTPHASE, P_BUSFREE; 5358c2ecf20Sopenharmony_ci call complete_target_cmd; 5368c2ecf20Sopenharmony_ci jmp poll_for_work; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_citarget_cmdphase: 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * The target has dropped ATN (doesn't want to abort or BDR) 5418c2ecf20Sopenharmony_ci * and we believe this selection to be valid. If the ring 5428c2ecf20Sopenharmony_ci * buffer for new commands is full, return busy or queue full. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci if ((ahc->features & AHC_HS_MAILBOX) != 0) { 5458c2ecf20Sopenharmony_ci and A, HOST_TQINPOS, HS_MAILBOX; 5468c2ecf20Sopenharmony_ci } else { 5478c2ecf20Sopenharmony_ci mov A, KERNEL_TQINPOS; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci cmp TQINPOS, A jne tqinfifo_has_space; 5508c2ecf20Sopenharmony_ci mvi P_STATUS|BSYO call change_phase; 5518c2ecf20Sopenharmony_ci test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; 5528c2ecf20Sopenharmony_ci mvi STATUS_QUEUE_FULL call target_outb; 5538c2ecf20Sopenharmony_ci jmp target_busfree_wait; 5548c2ecf20Sopenharmony_ci mvi STATUS_BUSY call target_outb; 5558c2ecf20Sopenharmony_ci jmp target_busfree_wait; 5568c2ecf20Sopenharmony_citqinfifo_has_space: 5578c2ecf20Sopenharmony_ci mvi P_COMMAND|BSYO call change_phase; 5588c2ecf20Sopenharmony_ci call target_inb; 5598c2ecf20Sopenharmony_ci mov A, DINDEX; 5608c2ecf20Sopenharmony_ci /* Store for host */ 5618c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 5628c2ecf20Sopenharmony_ci mov CCSCBRAM, A; 5638c2ecf20Sopenharmony_ci } else { 5648c2ecf20Sopenharmony_ci mov DFDAT, A; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * Determine the number of bytes to read 5698c2ecf20Sopenharmony_ci * based on the command group code via table lookup. 5708c2ecf20Sopenharmony_ci * We reuse the first 8 bytes of the TARG_SCSIRATE 5718c2ecf20Sopenharmony_ci * BIOS array for this table. Count is one less than 5728c2ecf20Sopenharmony_ci * the total for the command since we've already fetched 5738c2ecf20Sopenharmony_ci * the first byte. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci shr A, CMD_GROUP_CODE_SHIFT; 5768c2ecf20Sopenharmony_ci add SINDEX, CMDSIZE_TABLE, A; 5778c2ecf20Sopenharmony_ci mov A, SINDIR; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci test A, 0xFF jz command_phase_done; 5808c2ecf20Sopenharmony_ci or SXFRCTL0, SPIOEN; 5818c2ecf20Sopenharmony_cicommand_loop: 5828c2ecf20Sopenharmony_ci test SSTAT0, SPIORDY jz .; 5838c2ecf20Sopenharmony_ci cmp A, 1 jne . + 2; 5848c2ecf20Sopenharmony_ci and SXFRCTL0, ~SPIOEN; /* Last Byte */ 5858c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 5868c2ecf20Sopenharmony_ci mov CCSCBRAM, SCSIDATL; 5878c2ecf20Sopenharmony_ci } else { 5888c2ecf20Sopenharmony_ci mov DFDAT, SCSIDATL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci dec A; 5918c2ecf20Sopenharmony_ci test A, 0xFF jnz command_loop; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cicommand_phase_done: 5948c2ecf20Sopenharmony_ci and SEQ_FLAGS, ~CMDPHASE_PENDING; 5958c2ecf20Sopenharmony_ci jmp target_ITloop; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_citarget_dphase: 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * Data phases on the bus are from the 6008c2ecf20Sopenharmony_ci * perspective of the initiator. The dma 6018c2ecf20Sopenharmony_ci * code looks at LASTPHASE to determine the 6028c2ecf20Sopenharmony_ci * data direction of the DMA. Toggle it for 6038c2ecf20Sopenharmony_ci * target transfers. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci xor LASTPHASE, IOI, SCB_TARGET_DATA_DIR; 6068c2ecf20Sopenharmony_ci or SCB_TARGET_DATA_DIR, BSYO call change_phase; 6078c2ecf20Sopenharmony_ci jmp p_data; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_citarget_sphase: 6108c2ecf20Sopenharmony_ci mvi P_STATUS|BSYO call change_phase; 6118c2ecf20Sopenharmony_ci mvi LASTPHASE, P_STATUS; 6128c2ecf20Sopenharmony_ci mov SCB_SCSI_STATUS call target_outb; 6138c2ecf20Sopenharmony_ci /* XXX Watch for ATN or parity errors??? */ 6148c2ecf20Sopenharmony_ci mvi SCSISIGO, P_MESGIN|BSYO; 6158c2ecf20Sopenharmony_ci /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ 6168c2ecf20Sopenharmony_ci mov ALLZEROS call target_outb; 6178c2ecf20Sopenharmony_ci jmp target_busfree_wait; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cicomplete_target_cmd: 6208c2ecf20Sopenharmony_ci test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; 6218c2ecf20Sopenharmony_ci mov SCB_TAG jmp complete_post; 6228c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 6238c2ecf20Sopenharmony_ci /* Set the valid byte */ 6248c2ecf20Sopenharmony_ci mvi CCSCBADDR, 24; 6258c2ecf20Sopenharmony_ci mov CCSCBRAM, ALLONES; 6268c2ecf20Sopenharmony_ci mvi CCHCNT, 28; 6278c2ecf20Sopenharmony_ci or CCSCBCTL, CCSCBEN|CCSCBRESET; 6288c2ecf20Sopenharmony_ci test CCSCBCTL, CCSCBDONE jz .; 6298c2ecf20Sopenharmony_ci clr CCSCBCTL; 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci /* Set the valid byte */ 6328c2ecf20Sopenharmony_ci or DFCNTRL, FIFORESET; 6338c2ecf20Sopenharmony_ci mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ 6348c2ecf20Sopenharmony_ci mov DFDAT, ALLONES; 6358c2ecf20Sopenharmony_ci mvi 28 call set_hcnt; 6368c2ecf20Sopenharmony_ci or DFCNTRL, HDMAEN|FIFOFLUSH; 6378c2ecf20Sopenharmony_ci call dma_finish; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci inc TQINPOS; 6408c2ecf20Sopenharmony_ci mvi INTSTAT,CMDCMPLT ret; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_INITIATORROLE) != 0) { 6448c2ecf20Sopenharmony_ciinitiator_select: 6458c2ecf20Sopenharmony_ci or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; 6468c2ecf20Sopenharmony_ci /* 6478c2ecf20Sopenharmony_ci * As soon as we get a successful selection, the target 6488c2ecf20Sopenharmony_ci * should go into the message out phase since we have ATN 6498c2ecf20Sopenharmony_ci * asserted. 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_ci mvi MSG_OUT, MSG_IDENTIFYFLAG; 6528c2ecf20Sopenharmony_ci mvi SEQ_FLAGS, NO_CDB_SENT; 6538c2ecf20Sopenharmony_ci mvi CLRSINT0, CLRSELDO; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* 6568c2ecf20Sopenharmony_ci * Main loop for information transfer phases. Wait for the 6578c2ecf20Sopenharmony_ci * target to assert REQ before checking MSG, C/D and I/O for 6588c2ecf20Sopenharmony_ci * the bus phase. 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_cimesgin_phasemis: 6618c2ecf20Sopenharmony_ciITloop: 6628c2ecf20Sopenharmony_ci call phase_lock; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci mov A, LASTPHASE; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci test A, ~P_DATAIN jz p_data; 6678c2ecf20Sopenharmony_ci cmp A,P_COMMAND je p_command; 6688c2ecf20Sopenharmony_ci cmp A,P_MESGOUT je p_mesgout; 6698c2ecf20Sopenharmony_ci cmp A,P_STATUS je p_status; 6708c2ecf20Sopenharmony_ci cmp A,P_MESGIN je p_mesgin; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci mvi BAD_PHASE call set_seqint; 6738c2ecf20Sopenharmony_ci jmp ITloop; /* Try reading the bus again. */ 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ciawait_busfree: 6768c2ecf20Sopenharmony_ci and SIMODE1, ~ENBUSFREE; 6778c2ecf20Sopenharmony_ci mov NONE, SCSIDATL; /* Ack the last byte */ 6788c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 6798c2ecf20Sopenharmony_ci clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci and SXFRCTL0, ~SPIOEN; 6828c2ecf20Sopenharmony_ci mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; 6838c2ecf20Sopenharmony_ci test SSTAT1,REQINIT|BUSFREE jz .; 6848c2ecf20Sopenharmony_ci test SSTAT1, BUSFREE jnz poll_for_work; 6858c2ecf20Sopenharmony_ci mvi MISSED_BUSFREE call set_seqint; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ciclear_target_state: 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * We assume that the kernel driver may reset us 6918c2ecf20Sopenharmony_ci * at any time, even in the middle of a DMA, so 6928c2ecf20Sopenharmony_ci * clear DFCNTRL too. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci clr DFCNTRL; 6958c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * We don't know the target we will connect to, 6998c2ecf20Sopenharmony_ci * so default to narrow transfers to avoid 7008c2ecf20Sopenharmony_ci * parity problems. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 7038c2ecf20Sopenharmony_ci bmov SCSIRATE, ALLZEROS, 2; 7048c2ecf20Sopenharmony_ci } else { 7058c2ecf20Sopenharmony_ci clr SCSIRATE; 7068c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA) != 0) { 7078c2ecf20Sopenharmony_ci and SXFRCTL0, ~(FAST20); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci mvi LASTPHASE, P_BUSFREE; 7118c2ecf20Sopenharmony_ci /* clear target specific flags */ 7128c2ecf20Sopenharmony_ci mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cisg_advance: 7158c2ecf20Sopenharmony_ci clr A; /* add sizeof(struct scatter) */ 7168c2ecf20Sopenharmony_ci add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; 7178c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_SGPTR[1],A; 7188c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_SGPTR[2],A; 7198c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_SGPTR[3],A ret; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ciif ((ahc->features & AHC_CMD_CHAN) != 0) { 7228c2ecf20Sopenharmony_cidisable_ccsgen: 7238c2ecf20Sopenharmony_ci test CCSGCTL, CCSGEN jz return; 7248c2ecf20Sopenharmony_ci test CCSGCTL, CCSGDONE jz .; 7258c2ecf20Sopenharmony_cidisable_ccsgen_fetch_done: 7268c2ecf20Sopenharmony_ci clr CCSGCTL; 7278c2ecf20Sopenharmony_ci test CCSGCTL, CCSGEN jnz .; 7288c2ecf20Sopenharmony_ci ret; 7298c2ecf20Sopenharmony_ciidle_loop: 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * Do we need any more segments for this transfer? 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Did we just finish fetching segs? */ 7368c2ecf20Sopenharmony_ci cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* Are we actively fetching segments? */ 7398c2ecf20Sopenharmony_ci test CCSGCTL, CCSGEN jnz return; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* 7428c2ecf20Sopenharmony_ci * Do we have any prefetch left??? 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* 7478c2ecf20Sopenharmony_ci * Need to fetch segments, but we can only do that 7488c2ecf20Sopenharmony_ci * if the command channel is completely idle. Make 7498c2ecf20Sopenharmony_ci * sure we don't have an SCB prefetch going on. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci test CCSCBCTL, CCSCBEN jnz return; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* 7548c2ecf20Sopenharmony_ci * We fetch a "cacheline aligned" and sized amount of data 7558c2ecf20Sopenharmony_ci * so we don't end up referencing a non-existent page. 7568c2ecf20Sopenharmony_ci * Cacheline aligned is in quotes because the kernel will 7578c2ecf20Sopenharmony_ci * set the prefetch amount to a reasonable level if the 7588c2ecf20Sopenharmony_ci * cacheline size is unknown. 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci mvi CCHCNT, SG_PREFETCH_CNT; 7618c2ecf20Sopenharmony_ci and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; 7628c2ecf20Sopenharmony_ci bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; 7638c2ecf20Sopenharmony_ci mvi CCSGCTL, CCSGEN|CCSGRESET ret; 7648c2ecf20Sopenharmony_ciidle_sgfetch_complete: 7658c2ecf20Sopenharmony_ci call disable_ccsgen_fetch_done; 7668c2ecf20Sopenharmony_ci and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; 7678c2ecf20Sopenharmony_ciidle_sg_avail: 7688c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 7698c2ecf20Sopenharmony_ci /* Does the hardware have space for another SG entry? */ 7708c2ecf20Sopenharmony_ci test DFSTATUS, PRELOAD_AVAIL jz return; 7718c2ecf20Sopenharmony_ci bmov HADDR, CCSGRAM, 7; 7728c2ecf20Sopenharmony_ci bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; 7738c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 7748c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci call sg_advance; 7778c2ecf20Sopenharmony_ci mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 7788c2ecf20Sopenharmony_ci test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 7798c2ecf20Sopenharmony_ci or SINDEX, LAST_SEG; 7808c2ecf20Sopenharmony_ci mov SG_CACHE_PRE, SINDEX; 7818c2ecf20Sopenharmony_ci /* Load the segment */ 7828c2ecf20Sopenharmony_ci or DFCNTRL, PRELOADEN; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci ret; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ciif ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 7888c2ecf20Sopenharmony_ci/* 7898c2ecf20Sopenharmony_ci * Calculate the trailing portion of this S/G segment that cannot 7908c2ecf20Sopenharmony_ci * be transferred using memory write and invalidate PCI transactions. 7918c2ecf20Sopenharmony_ci * XXX Can we optimize this for PCI writes only??? 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_cicalc_mwi_residual: 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * If the ending address is on a cacheline boundary, 7968c2ecf20Sopenharmony_ci * there is no need for an extra segment. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci mov A, HCNT[0]; 7998c2ecf20Sopenharmony_ci add A, A, HADDR[0]; 8008c2ecf20Sopenharmony_ci and A, CACHESIZE_MASK; 8018c2ecf20Sopenharmony_ci test A, 0xFF jz return; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * If the transfer is less than a cachline, 8058c2ecf20Sopenharmony_ci * there is no need for an extra segment. 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci test HCNT[1], 0xFF jnz calc_mwi_residual_final; 8088c2ecf20Sopenharmony_ci test HCNT[2], 0xFF jnz calc_mwi_residual_final; 8098c2ecf20Sopenharmony_ci add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; 8108c2ecf20Sopenharmony_ci jnc return; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cicalc_mwi_residual_final: 8138c2ecf20Sopenharmony_ci mov MWI_RESIDUAL, A; 8148c2ecf20Sopenharmony_ci not A; 8158c2ecf20Sopenharmony_ci inc A; 8168c2ecf20Sopenharmony_ci add HCNT[0], A; 8178c2ecf20Sopenharmony_ci adc HCNT[1], -1; 8188c2ecf20Sopenharmony_ci adc HCNT[2], -1 ret; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cip_data: 8228c2ecf20Sopenharmony_ci test SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; 8238c2ecf20Sopenharmony_ci mvi PROTO_VIOLATION call set_seqint; 8248c2ecf20Sopenharmony_cip_data_allowed: 8258c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 8268c2ecf20Sopenharmony_ci mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; 8278c2ecf20Sopenharmony_ci } else { 8288c2ecf20Sopenharmony_ci mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci test LASTPHASE, IOI jnz . + 2; 8318c2ecf20Sopenharmony_ci or DMAPARAMS, DIRECTION; 8328c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 8338c2ecf20Sopenharmony_ci /* We don't have any valid S/G elements */ 8348c2ecf20Sopenharmony_ci mvi CCSGADDR, SG_PREFETCH_CNT; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE jz data_phase_initialize; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* 8398c2ecf20Sopenharmony_ci * If we re-enter the data phase after going through another 8408c2ecf20Sopenharmony_ci * phase, our transfer location has almost certainly been 8418c2ecf20Sopenharmony_ci * corrupted by the interveining, non-data, transfers. Ask 8428c2ecf20Sopenharmony_ci * the host driver to fix us up based on the transfer residual. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci mvi PDATA_REINIT call set_seqint; 8458c2ecf20Sopenharmony_ci jmp data_phase_loop; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cidata_phase_initialize: 8488c2ecf20Sopenharmony_ci /* We have seen a data phase for the first time */ 8498c2ecf20Sopenharmony_ci or SEQ_FLAGS, DPHASE; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * Initialize the DMA address and counter from the SCB. 8538c2ecf20Sopenharmony_ci * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG 8548c2ecf20Sopenharmony_ci * flag in the highest byte of the data count. We cannot 8558c2ecf20Sopenharmony_ci * modify the saved values in the SCB until we see a save 8568c2ecf20Sopenharmony_ci * data pointers message. 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 8598c2ecf20Sopenharmony_ci /* The lowest address byte must be loaded last. */ 8608c2ecf20Sopenharmony_ci mov SCB_DATACNT[3] call set_hhaddr; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 8638c2ecf20Sopenharmony_ci bmov HADDR, SCB_DATAPTR, 7; 8648c2ecf20Sopenharmony_ci bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; 8658c2ecf20Sopenharmony_ci } else { 8668c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 8678c2ecf20Sopenharmony_ci mvi SCB_DATAPTR call bcopy_7; 8688c2ecf20Sopenharmony_ci mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; 8698c2ecf20Sopenharmony_ci mvi SCB_DATACNT + 3 call bcopy_5; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { 8728c2ecf20Sopenharmony_ci call calc_mwi_residual; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) == 0) { 8778c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 8788c2ecf20Sopenharmony_ci bmov STCNT, HCNT, 3; 8798c2ecf20Sopenharmony_ci } else { 8808c2ecf20Sopenharmony_ci call set_stcnt_from_hcnt; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cidata_phase_loop: 8858c2ecf20Sopenharmony_ci /* Guard against overruns */ 8868c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * Turn on `Bit Bucket' mode, wait until the target takes 8908c2ecf20Sopenharmony_ci * us to another phase, and then notify the host. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci and DMAPARAMS, DIRECTION; 8938c2ecf20Sopenharmony_ci mov DFCNTRL, DMAPARAMS; 8948c2ecf20Sopenharmony_ci or SXFRCTL1,BITBUCKET; 8958c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 8968c2ecf20Sopenharmony_ci test SSTAT1,PHASEMIS jz .; 8978c2ecf20Sopenharmony_ci } else { 8988c2ecf20Sopenharmony_ci test SCSIPHASE, DATA_PHASE_MASK jnz .; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci and SXFRCTL1, ~BITBUCKET; 9018c2ecf20Sopenharmony_ci mvi DATA_OVERRUN call set_seqint; 9028c2ecf20Sopenharmony_ci jmp ITloop; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cidata_phase_inbounds: 9058c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 9068c2ecf20Sopenharmony_ci mov SINDEX, SCB_RESIDUAL_SGPTR[0]; 9078c2ecf20Sopenharmony_ci test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; 9088c2ecf20Sopenharmony_ci or SINDEX, LAST_SEG; 9098c2ecf20Sopenharmony_ci mov SG_CACHE_PRE, SINDEX; 9108c2ecf20Sopenharmony_ci mov DFCNTRL, DMAPARAMS; 9118c2ecf20Sopenharmony_ciultra2_dma_loop: 9128c2ecf20Sopenharmony_ci call idle_loop; 9138c2ecf20Sopenharmony_ci /* 9148c2ecf20Sopenharmony_ci * The transfer is complete if either the last segment 9158c2ecf20Sopenharmony_ci * completes or the target changes phase. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; 9188c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 9198c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 9208c2ecf20Sopenharmony_ci /* 9218c2ecf20Sopenharmony_ci * As a target, we control the phases, 9228c2ecf20Sopenharmony_ci * so ignore PHASEMIS. 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci test SSTAT0, TARGET jnz ultra2_dma_loop; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_INITIATORROLE) != 0) { 9278c2ecf20Sopenharmony_ci test SSTAT1,PHASEMIS jz ultra2_dma_loop; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci } else { 9308c2ecf20Sopenharmony_ci test DFCNTRL, SCSIEN jnz ultra2_dma_loop; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ciultra2_dmafinish: 9348c2ecf20Sopenharmony_ci /* 9358c2ecf20Sopenharmony_ci * The transfer has terminated either due to a phase 9368c2ecf20Sopenharmony_ci * change, and/or the completion of the last segment. 9378c2ecf20Sopenharmony_ci * We have two goals here. Do as much other work 9388c2ecf20Sopenharmony_ci * as possible while the data fifo drains on a read 9398c2ecf20Sopenharmony_ci * and respond as quickly as possible to the standard 9408c2ecf20Sopenharmony_ci * messages (save data pointers/disconnect and command 9418c2ecf20Sopenharmony_ci * complete) that usually follow a data phase. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * On chips with broken auto-flush, start 9468c2ecf20Sopenharmony_ci * the flushing process now. We'll poke 9478c2ecf20Sopenharmony_ci * the chip from time to time to keep the 9488c2ecf20Sopenharmony_ci * flush process going as we complete the 9498c2ecf20Sopenharmony_ci * data phase. 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_ci or DFCNTRL, FIFOFLUSH; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci * We assume that, even though data may still be 9558c2ecf20Sopenharmony_ci * transferring to the host, that the SCSI side of 9568c2ecf20Sopenharmony_ci * the DMA engine is now in a static state. This 9578c2ecf20Sopenharmony_ci * allows us to update our notion of where we are 9588c2ecf20Sopenharmony_ci * in this transfer. 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * If, by chance, we stopped before being able 9618c2ecf20Sopenharmony_ci * to fetch additional segments for this transfer, 9628c2ecf20Sopenharmony_ci * yet the last S/G was completely exhausted, 9638c2ecf20Sopenharmony_ci * call our idle loop until it is able to load 9648c2ecf20Sopenharmony_ci * another segment. This will allow us to immediately 9658c2ecf20Sopenharmony_ci * pickup on the next segment on the next data phase. 9668c2ecf20Sopenharmony_ci * 9678c2ecf20Sopenharmony_ci * If we happened to stop on the last segment, then 9688c2ecf20Sopenharmony_ci * our residual information is still correct from 9698c2ecf20Sopenharmony_ci * the idle loop and there is no need to perform 9708c2ecf20Sopenharmony_ci * any fixups. 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ciultra2_ensure_sg: 9738c2ecf20Sopenharmony_ci test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; 9748c2ecf20Sopenharmony_ci /* Record if we've consumed all S/G entries */ 9758c2ecf20Sopenharmony_ci test SSTAT2, SHVALID jnz residuals_correct; 9768c2ecf20Sopenharmony_ci or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 9778c2ecf20Sopenharmony_ci jmp residuals_correct; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ciultra2_shvalid: 9808c2ecf20Sopenharmony_ci test SSTAT2, SHVALID jnz sgptr_fixup; 9818c2ecf20Sopenharmony_ci call idle_loop; 9828c2ecf20Sopenharmony_ci jmp ultra2_ensure_sg; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cisgptr_fixup: 9858c2ecf20Sopenharmony_ci /* 9868c2ecf20Sopenharmony_ci * Fixup the residual next S/G pointer. The S/G preload 9878c2ecf20Sopenharmony_ci * feature of the chip allows us to load two elements 9888c2ecf20Sopenharmony_ci * in addition to the currently active element. We 9898c2ecf20Sopenharmony_ci * store the bottom byte of the next S/G pointer in 9908c2ecf20Sopenharmony_ci * the SG_CACEPTR register so we can restore the 9918c2ecf20Sopenharmony_ci * correct value when the DMA completes. If the next 9928c2ecf20Sopenharmony_ci * sg ptr value has advanced to the point where higher 9938c2ecf20Sopenharmony_ci * bytes in the address have been affected, fix them 9948c2ecf20Sopenharmony_ci * too. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; 9978c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; 9988c2ecf20Sopenharmony_ci add SCB_RESIDUAL_SGPTR[1], -1; 9998c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_SGPTR[2], -1; 10008c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_SGPTR[3], -1; 10018c2ecf20Sopenharmony_cisgptr_fixup_done: 10028c2ecf20Sopenharmony_ci and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; 10038c2ecf20Sopenharmony_ci /* We are not the last seg */ 10048c2ecf20Sopenharmony_ci and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG; 10058c2ecf20Sopenharmony_ciresiduals_correct: 10068c2ecf20Sopenharmony_ci /* 10078c2ecf20Sopenharmony_ci * Go ahead and shut down the DMA engine now. 10088c2ecf20Sopenharmony_ci * In the future, we'll want to handle end of 10098c2ecf20Sopenharmony_ci * transfer messages prior to doing this, but this 10108c2ecf20Sopenharmony_ci * requires similar restructuring for pre-ULTRA2 10118c2ecf20Sopenharmony_ci * controllers. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_ci test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; 10148c2ecf20Sopenharmony_ciultra2_fifoflush: 10158c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 10168c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * On Rev A of the aic7890, the autoflush 10198c2ecf20Sopenharmony_ci * feature doesn't function correctly. 10208c2ecf20Sopenharmony_ci * Perform an explicit manual flush. During 10218c2ecf20Sopenharmony_ci * a manual flush, the FIFOEMP bit becomes 10228c2ecf20Sopenharmony_ci * true every time the PCI FIFO empties 10238c2ecf20Sopenharmony_ci * regardless of the state of the SCSI FIFO. 10248c2ecf20Sopenharmony_ci * It can take up to 4 clock cycles for the 10258c2ecf20Sopenharmony_ci * SCSI FIFO to get data into the PCI FIFO 10268c2ecf20Sopenharmony_ci * and for FIFOEMP to de-assert. Here we 10278c2ecf20Sopenharmony_ci * guard against this condition by making 10288c2ecf20Sopenharmony_ci * sure the FIFOEMP bit stays on for 5 full 10298c2ecf20Sopenharmony_ci * clock cycles. 10308c2ecf20Sopenharmony_ci */ 10318c2ecf20Sopenharmony_ci or DFCNTRL, FIFOFLUSH; 10328c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 10338c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 10348c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 10358c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz ultra2_fifoflush; 10388c2ecf20Sopenharmony_ci } else { 10398c2ecf20Sopenharmony_ci /* 10408c2ecf20Sopenharmony_ci * We enable the auto-ack feature on DT capable 10418c2ecf20Sopenharmony_ci * controllers. This means that the controller may 10428c2ecf20Sopenharmony_ci * have already transferred some overrun bytes into 10438c2ecf20Sopenharmony_ci * the data FIFO and acked them on the bus. The only 10448c2ecf20Sopenharmony_ci * way to detect this situation is to wait for 10458c2ecf20Sopenharmony_ci * LAST_SEG_DONE to come true on a completed transfer 10468c2ecf20Sopenharmony_ci * and then test to see if the data FIFO is non-empty. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL 10498c2ecf20Sopenharmony_ci jz ultra2_wait_fifoemp; 10508c2ecf20Sopenharmony_ci test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * FIFOEMP can lag LAST_SEG_DONE. Wait a few 10538c2ecf20Sopenharmony_ci * clocks before calling this an overrun. 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 10568c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 10578c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; 10588c2ecf20Sopenharmony_ci /* Overrun */ 10598c2ecf20Sopenharmony_ci jmp data_phase_loop; 10608c2ecf20Sopenharmony_ciultra2_wait_fifoemp: 10618c2ecf20Sopenharmony_ci test DFSTATUS, FIFOEMP jz .; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ciultra2_fifoempty: 10648c2ecf20Sopenharmony_ci /* Don't clobber an inprogress host data transfer */ 10658c2ecf20Sopenharmony_ci test DFSTATUS, MREQPEND jnz ultra2_fifoempty; 10668c2ecf20Sopenharmony_ciultra2_dmahalt: 10678c2ecf20Sopenharmony_ci and DFCNTRL, ~(SCSIEN|HDMAEN); 10688c2ecf20Sopenharmony_ci test DFCNTRL, SCSIEN|HDMAEN jnz .; 10698c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 10708c2ecf20Sopenharmony_ci /* 10718c2ecf20Sopenharmony_ci * Keep HHADDR cleared for future, 32bit addressed 10728c2ecf20Sopenharmony_ci * only, DMA operations. 10738c2ecf20Sopenharmony_ci * 10748c2ecf20Sopenharmony_ci * Due to bayonette style S/G handling, our residual 10758c2ecf20Sopenharmony_ci * data must be "fixed up" once the transfer is halted. 10768c2ecf20Sopenharmony_ci * Here we fixup the HSHADDR stored in the high byte 10778c2ecf20Sopenharmony_ci * of the residual data cnt. By postponing the fixup, 10788c2ecf20Sopenharmony_ci * we can batch the clearing of HADDR with the fixup. 10798c2ecf20Sopenharmony_ci * If we halted on the last segment, the residual is 10808c2ecf20Sopenharmony_ci * already correct. If we are not on the last 10818c2ecf20Sopenharmony_ci * segment, copy the high address directly from HSHADDR. 10828c2ecf20Sopenharmony_ci * We don't need to worry about maintaining the 10838c2ecf20Sopenharmony_ci * SG_LAST_SEG flag as it will always be false in the 10848c2ecf20Sopenharmony_ci * case where an update is required. 10858c2ecf20Sopenharmony_ci */ 10868c2ecf20Sopenharmony_ci or DSCOMMAND1, HADDLDSEL0; 10878c2ecf20Sopenharmony_ci test SG_CACHE_SHADOW, LAST_SEG jnz . + 2; 10888c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[3], SHADDR; 10898c2ecf20Sopenharmony_ci clr HADDR; 10908c2ecf20Sopenharmony_ci and DSCOMMAND1, ~HADDLDSEL0; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci } else { 10938c2ecf20Sopenharmony_ci /* If we are the last SG block, tell the hardware. */ 10948c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 10958c2ecf20Sopenharmony_ci && ahc->pci_cachesize != 0) { 10968c2ecf20Sopenharmony_ci test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; 10998c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 11008c2ecf20Sopenharmony_ci test SSTAT0, TARGET jz dma_last_sg; 11018c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { 11028c2ecf20Sopenharmony_ci test DMAPARAMS, DIRECTION jz dma_mid_sg; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_cidma_last_sg: 11068c2ecf20Sopenharmony_ci and DMAPARAMS, ~WIDEODD; 11078c2ecf20Sopenharmony_cidma_mid_sg: 11088c2ecf20Sopenharmony_ci /* Start DMA data transfer. */ 11098c2ecf20Sopenharmony_ci mov DFCNTRL, DMAPARAMS; 11108c2ecf20Sopenharmony_cidma_loop: 11118c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 11128c2ecf20Sopenharmony_ci call idle_loop; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci test SSTAT0,DMADONE jnz dma_dmadone; 11158c2ecf20Sopenharmony_ci test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ 11168c2ecf20Sopenharmony_cidma_phasemis: 11178c2ecf20Sopenharmony_ci /* 11188c2ecf20Sopenharmony_ci * We will be "done" DMAing when the transfer count goes to 11198c2ecf20Sopenharmony_ci * zero, or the target changes the phase (in light of this, 11208c2ecf20Sopenharmony_ci * it makes sense that the DMA circuitry doesn't ACK when 11218c2ecf20Sopenharmony_ci * PHASEMIS is active). If we are doing a SCSI->Host transfer, 11228c2ecf20Sopenharmony_ci * the data FIFO should be flushed auto-magically on STCNT=0 11238c2ecf20Sopenharmony_ci * or a phase change, so just wait for FIFO empty status. 11248c2ecf20Sopenharmony_ci */ 11258c2ecf20Sopenharmony_cidma_checkfifo: 11268c2ecf20Sopenharmony_ci test DFCNTRL,DIRECTION jnz dma_fifoempty; 11278c2ecf20Sopenharmony_cidma_fifoflush: 11288c2ecf20Sopenharmony_ci test DFSTATUS,FIFOEMP jz dma_fifoflush; 11298c2ecf20Sopenharmony_cidma_fifoempty: 11308c2ecf20Sopenharmony_ci /* Don't clobber an inprogress host data transfer */ 11318c2ecf20Sopenharmony_ci test DFSTATUS, MREQPEND jnz dma_fifoempty; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* 11348c2ecf20Sopenharmony_ci * Now shut off the DMA and make sure that the DMA 11358c2ecf20Sopenharmony_ci * hardware has actually stopped. Touching the DMA 11368c2ecf20Sopenharmony_ci * counters, etc. while a DMA is active will result 11378c2ecf20Sopenharmony_ci * in an ILLSADDR exception. 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_cidma_dmadone: 11408c2ecf20Sopenharmony_ci and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 11418c2ecf20Sopenharmony_cidma_halt: 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * Some revisions of the aic78XX have a problem where, if the 11448c2ecf20Sopenharmony_ci * data fifo is full, but the PCI input latch is not empty, 11458c2ecf20Sopenharmony_ci * HDMAEN cannot be cleared. The fix used here is to drain 11468c2ecf20Sopenharmony_ci * the prefetched but unused data from the data fifo until 11478c2ecf20Sopenharmony_ci * there is space for the input latch to drain. 11488c2ecf20Sopenharmony_ci */ 11498c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 11508c2ecf20Sopenharmony_ci mov NONE, DFDAT; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* See if we have completed this last segment */ 11558c2ecf20Sopenharmony_ci test STCNT[0], 0xff jnz data_phase_finish; 11568c2ecf20Sopenharmony_ci test STCNT[1], 0xff jnz data_phase_finish; 11578c2ecf20Sopenharmony_ci test STCNT[2], 0xff jnz data_phase_finish; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* 11608c2ecf20Sopenharmony_ci * Advance the scatter-gather pointers if needed 11618c2ecf20Sopenharmony_ci */ 11628c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 11638c2ecf20Sopenharmony_ci && ahc->pci_cachesize != 0) { 11648c2ecf20Sopenharmony_ci test MWI_RESIDUAL, 0xFF jz no_mwi_resid; 11658c2ecf20Sopenharmony_ci /* 11668c2ecf20Sopenharmony_ci * Reload HADDR from SHADDR and setup the 11678c2ecf20Sopenharmony_ci * count to be the size of our residual. 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 11708c2ecf20Sopenharmony_ci bmov HADDR, SHADDR, 4; 11718c2ecf20Sopenharmony_ci mov HCNT, MWI_RESIDUAL; 11728c2ecf20Sopenharmony_ci bmov HCNT[1], ALLZEROS, 2; 11738c2ecf20Sopenharmony_ci } else { 11748c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 11758c2ecf20Sopenharmony_ci mvi SHADDR call bcopy_4; 11768c2ecf20Sopenharmony_ci mov MWI_RESIDUAL call set_hcnt; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci clr MWI_RESIDUAL; 11798c2ecf20Sopenharmony_ci jmp sg_load_done; 11808c2ecf20Sopenharmony_cino_mwi_resid: 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; 11838c2ecf20Sopenharmony_ci or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; 11848c2ecf20Sopenharmony_ci jmp data_phase_finish; 11858c2ecf20Sopenharmony_cisg_load: 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * Load the next SG element's data address and length 11888c2ecf20Sopenharmony_ci * into the DMA engine. If we don't have hardware 11898c2ecf20Sopenharmony_ci * to perform a prefetch, we'll have to fetch the 11908c2ecf20Sopenharmony_ci * segment from host memory first. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 11938c2ecf20Sopenharmony_ci /* Wait for the idle loop to complete */ 11948c2ecf20Sopenharmony_ci test CCSGCTL, CCSGEN jz . + 3; 11958c2ecf20Sopenharmony_ci call idle_loop; 11968c2ecf20Sopenharmony_ci test CCSGCTL, CCSGEN jnz . - 1; 11978c2ecf20Sopenharmony_ci bmov HADDR, CCSGRAM, 7; 11988c2ecf20Sopenharmony_ci /* 11998c2ecf20Sopenharmony_ci * Workaround for flaky external SCB RAM 12008c2ecf20Sopenharmony_ci * on certain aic7895 setups. It seems 12018c2ecf20Sopenharmony_ci * unable to handle direct transfers from 12028c2ecf20Sopenharmony_ci * S/G ram to certain SCB locations. 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci mov SINDEX, CCSGRAM; 12058c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[3], SINDEX; 12068c2ecf20Sopenharmony_ci } else { 12078c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 12088c2ecf20Sopenharmony_ci mov ALLZEROS call set_hhaddr; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 12118c2ecf20Sopenharmony_ci mvi SCB_RESIDUAL_SGPTR call bcopy_4; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci mvi SG_SIZEOF call set_hcnt; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci call dma_finish; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 12208c2ecf20Sopenharmony_ci call dfdat_in_7; 12218c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[3], DFDAT; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 12258c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* 12288c2ecf20Sopenharmony_ci * The lowest address byte must be loaded 12298c2ecf20Sopenharmony_ci * last as it triggers the computation of 12308c2ecf20Sopenharmony_ci * some items in the PCI block. The ULTRA2 12318c2ecf20Sopenharmony_ci * chips do this on PRELOAD. 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci mov HADDR, HADDR; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 12368c2ecf20Sopenharmony_ci && ahc->pci_cachesize != 0) { 12378c2ecf20Sopenharmony_ci call calc_mwi_residual; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Point to the new next sg in memory */ 12418c2ecf20Sopenharmony_ci call sg_advance; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cisg_load_done: 12448c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 12458c2ecf20Sopenharmony_ci bmov STCNT, HCNT, 3; 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci call set_stcnt_from_hcnt; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 12518c2ecf20Sopenharmony_ci test SSTAT0, TARGET jnz data_phase_loop; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_cidata_phase_finish: 12558c2ecf20Sopenharmony_ci /* 12568c2ecf20Sopenharmony_ci * If the target has left us in data phase, loop through 12578c2ecf20Sopenharmony_ci * the dma code again. In the case of ULTRA2 adapters, 12588c2ecf20Sopenharmony_ci * we should only loop if there is a data overrun. For 12598c2ecf20Sopenharmony_ci * all other adapters, we'll loop after each S/G element 12608c2ecf20Sopenharmony_ci * is loaded as well as if there is an overrun. 12618c2ecf20Sopenharmony_ci */ 12628c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 12638c2ecf20Sopenharmony_ci test SSTAT0, TARGET jnz data_phase_done; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_INITIATORROLE) != 0) { 12668c2ecf20Sopenharmony_ci test SSTAT1, REQINIT jz .; 12678c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 12688c2ecf20Sopenharmony_ci test SSTAT1,PHASEMIS jz data_phase_loop; 12698c2ecf20Sopenharmony_ci } else { 12708c2ecf20Sopenharmony_ci test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_cidata_phase_done: 12758c2ecf20Sopenharmony_ci /* 12768c2ecf20Sopenharmony_ci * After a DMA finishes, save the SG and STCNT residuals back into 12778c2ecf20Sopenharmony_ci * the SCB. We use STCNT instead of HCNT, since it's a reflection 12788c2ecf20Sopenharmony_ci * of how many bytes were transferred on the SCSI (as opposed to the 12798c2ecf20Sopenharmony_ci * host) bus. 12808c2ecf20Sopenharmony_ci */ 12818c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 12828c2ecf20Sopenharmony_ci /* Kill off any pending prefetch */ 12838c2ecf20Sopenharmony_ci call disable_ccsgen; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) == 0) { 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * Clear the high address byte so that all other DMA 12898c2ecf20Sopenharmony_ci * operations, which use 32bit addressing, can assume 12908c2ecf20Sopenharmony_ci * HHADDR is 0. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 12938c2ecf20Sopenharmony_ci mov ALLZEROS call set_hhaddr; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* 12988c2ecf20Sopenharmony_ci * Update our residual information before the information is 12998c2ecf20Sopenharmony_ci * lost by some other type of SCSI I/O (e.g. PIO). If we have 13008c2ecf20Sopenharmony_ci * transferred all data, no update is needed. 13018c2ecf20Sopenharmony_ci * 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done; 13048c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 13058c2ecf20Sopenharmony_ci && ahc->pci_cachesize != 0) { 13068c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 13078c2ecf20Sopenharmony_ci test MWI_RESIDUAL, 0xFF jz bmov_resid; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci mov A, MWI_RESIDUAL; 13108c2ecf20Sopenharmony_ci add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; 13118c2ecf20Sopenharmony_ci clr A; 13128c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; 13138c2ecf20Sopenharmony_ci adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; 13148c2ecf20Sopenharmony_ci clr MWI_RESIDUAL; 13158c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 13168c2ecf20Sopenharmony_ci jmp . + 2; 13178c2ecf20Sopenharmony_cibmov_resid: 13188c2ecf20Sopenharmony_ci bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 13218c2ecf20Sopenharmony_ci bmov SCB_RESIDUAL_DATACNT, STCNT, 3; 13228c2ecf20Sopenharmony_ci } else { 13238c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; 13248c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; 13258c2ecf20Sopenharmony_ci mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ciresidual_update_done: 13288c2ecf20Sopenharmony_ci /* 13298c2ecf20Sopenharmony_ci * Since we've been through a data phase, the SCB_RESID* fields 13308c2ecf20Sopenharmony_ci * are now initialized. Clear the full residual flag. 13318c2ecf20Sopenharmony_ci */ 13328c2ecf20Sopenharmony_ci and SCB_SGPTR[0], ~SG_FULL_RESID; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 13358c2ecf20Sopenharmony_ci /* Clear the channel in case we return to data phase later */ 13368c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 13378c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_TARGETROLE) != 0) { 13418c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE_PENDING jz ITloop; 13428c2ecf20Sopenharmony_ci and SEQ_FLAGS, ~DPHASE_PENDING; 13438c2ecf20Sopenharmony_ci /* 13448c2ecf20Sopenharmony_ci * For data-in phases, wait for any pending acks from the 13458c2ecf20Sopenharmony_ci * initiator before changing phase. We only need to 13468c2ecf20Sopenharmony_ci * send Ignore Wide Residue messages for data-in phases. 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci test DFCNTRL, DIRECTION jz target_ITloop; 13498c2ecf20Sopenharmony_ci test SSTAT1, REQINIT jnz .; 13508c2ecf20Sopenharmony_ci test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop; 13518c2ecf20Sopenharmony_ci test SCSIRATE, WIDEXFER jz target_ITloop; 13528c2ecf20Sopenharmony_ci /* 13538c2ecf20Sopenharmony_ci * Issue an Ignore Wide Residue Message. 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci mvi P_MESGIN|BSYO call change_phase; 13568c2ecf20Sopenharmony_ci mvi MSG_IGN_WIDE_RESIDUE call target_outb; 13578c2ecf20Sopenharmony_ci mvi 1 call target_outb; 13588c2ecf20Sopenharmony_ci jmp target_ITloop; 13598c2ecf20Sopenharmony_ci } else { 13608c2ecf20Sopenharmony_ci jmp ITloop; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_INITIATORROLE) != 0) { 13648c2ecf20Sopenharmony_ci/* 13658c2ecf20Sopenharmony_ci * Command phase. Set up the DMA registers and let 'er rip. 13668c2ecf20Sopenharmony_ci */ 13678c2ecf20Sopenharmony_cip_command: 13688c2ecf20Sopenharmony_ci test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; 13698c2ecf20Sopenharmony_ci mvi PROTO_VIOLATION call set_seqint; 13708c2ecf20Sopenharmony_cip_command_okay: 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 13738c2ecf20Sopenharmony_ci bmov HCNT[0], SCB_CDB_LEN, 1; 13748c2ecf20Sopenharmony_ci bmov HCNT[1], ALLZEROS, 2; 13758c2ecf20Sopenharmony_ci mvi SG_CACHE_PRE, LAST_SEG; 13768c2ecf20Sopenharmony_ci } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 13778c2ecf20Sopenharmony_ci bmov STCNT[0], SCB_CDB_LEN, 1; 13788c2ecf20Sopenharmony_ci bmov STCNT[1], ALLZEROS, 2; 13798c2ecf20Sopenharmony_ci } else { 13808c2ecf20Sopenharmony_ci mov STCNT[0], SCB_CDB_LEN; 13818c2ecf20Sopenharmony_ci clr STCNT[1]; 13828c2ecf20Sopenharmony_ci clr STCNT[2]; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci add NONE, -13, SCB_CDB_LEN; 13858c2ecf20Sopenharmony_ci mvi SCB_CDB_STORE jnc p_command_embedded; 13868c2ecf20Sopenharmony_cip_command_from_host: 13878c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 13888c2ecf20Sopenharmony_ci bmov HADDR[0], SCB_CDB_PTR, 4; 13898c2ecf20Sopenharmony_ci mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); 13908c2ecf20Sopenharmony_ci } else { 13918c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 13928c2ecf20Sopenharmony_ci bmov HADDR[0], SCB_CDB_PTR, 4; 13938c2ecf20Sopenharmony_ci bmov HCNT, STCNT, 3; 13948c2ecf20Sopenharmony_ci } else { 13958c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 13968c2ecf20Sopenharmony_ci mvi SCB_CDB_PTR call bcopy_4; 13978c2ecf20Sopenharmony_ci mov SCB_CDB_LEN call set_hcnt; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci jmp p_command_xfer; 14028c2ecf20Sopenharmony_cip_command_embedded: 14038c2ecf20Sopenharmony_ci /* 14048c2ecf20Sopenharmony_ci * The data fifo seems to require 4 byte aligned 14058c2ecf20Sopenharmony_ci * transfers from the sequencer. Force this to 14068c2ecf20Sopenharmony_ci * be the case by clearing HADDR[0] even though 14078c2ecf20Sopenharmony_ci * we aren't going to touch host memory. 14088c2ecf20Sopenharmony_ci */ 14098c2ecf20Sopenharmony_ci clr HADDR[0]; 14108c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 14118c2ecf20Sopenharmony_ci mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); 14128c2ecf20Sopenharmony_ci bmov DFDAT, SCB_CDB_STORE, 12; 14138c2ecf20Sopenharmony_ci } else if ((ahc->features & AHC_CMD_CHAN) != 0) { 14148c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 14158c2ecf20Sopenharmony_ci /* 14168c2ecf20Sopenharmony_ci * On the 7895 the data FIFO will 14178c2ecf20Sopenharmony_ci * get corrupted if you try to dump 14188c2ecf20Sopenharmony_ci * data from external SCB memory into 14198c2ecf20Sopenharmony_ci * the FIFO while it is enabled. So, 14208c2ecf20Sopenharmony_ci * fill the fifo and then enable SCSI 14218c2ecf20Sopenharmony_ci * transfers. 14228c2ecf20Sopenharmony_ci */ 14238c2ecf20Sopenharmony_ci mvi DFCNTRL, (DIRECTION|FIFORESET); 14248c2ecf20Sopenharmony_ci } else { 14258c2ecf20Sopenharmony_ci mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci bmov DFDAT, SCB_CDB_STORE, 12; 14288c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 14298c2ecf20Sopenharmony_ci mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); 14308c2ecf20Sopenharmony_ci } else { 14318c2ecf20Sopenharmony_ci or DFCNTRL, FIFOFLUSH; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci } else { 14348c2ecf20Sopenharmony_ci mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); 14358c2ecf20Sopenharmony_ci call copy_to_fifo_6; 14368c2ecf20Sopenharmony_ci call copy_to_fifo_6; 14378c2ecf20Sopenharmony_ci or DFCNTRL, FIFOFLUSH; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_cip_command_xfer: 14408c2ecf20Sopenharmony_ci and SEQ_FLAGS, ~NO_CDB_SENT; 14418c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 14428c2ecf20Sopenharmony_ci test SSTAT0, SDONE jnz . + 2; 14438c2ecf20Sopenharmony_ci test SSTAT1, PHASEMIS jz . - 1; 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * Wait for our ACK to go-away on it's own 14468c2ecf20Sopenharmony_ci * instead of being killed by SCSIEN getting cleared. 14478c2ecf20Sopenharmony_ci */ 14488c2ecf20Sopenharmony_ci test SCSISIGI, ACKI jnz .; 14498c2ecf20Sopenharmony_ci } else { 14508c2ecf20Sopenharmony_ci test DFCNTRL, SCSIEN jnz .; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci test SSTAT0, SDONE jnz p_command_successful; 14538c2ecf20Sopenharmony_ci /* 14548c2ecf20Sopenharmony_ci * Don't allow a data phase if the command 14558c2ecf20Sopenharmony_ci * was not fully transferred. 14568c2ecf20Sopenharmony_ci */ 14578c2ecf20Sopenharmony_ci or SEQ_FLAGS, NO_CDB_SENT; 14588c2ecf20Sopenharmony_cip_command_successful: 14598c2ecf20Sopenharmony_ci and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); 14608c2ecf20Sopenharmony_ci test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; 14618c2ecf20Sopenharmony_ci jmp ITloop; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci/* 14648c2ecf20Sopenharmony_ci * Status phase. Wait for the data byte to appear, then read it 14658c2ecf20Sopenharmony_ci * and store it into the SCB. 14668c2ecf20Sopenharmony_ci */ 14678c2ecf20Sopenharmony_cip_status: 14688c2ecf20Sopenharmony_ci test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; 14698c2ecf20Sopenharmony_cip_status_okay: 14708c2ecf20Sopenharmony_ci mov SCB_SCSI_STATUS, SCSIDATL; 14718c2ecf20Sopenharmony_ci or SCB_CONTROL, STATUS_RCVD; 14728c2ecf20Sopenharmony_ci jmp ITloop; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci/* 14758c2ecf20Sopenharmony_ci * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full 14768c2ecf20Sopenharmony_ci * indentify message sequence and send it to the target. The host may 14778c2ecf20Sopenharmony_ci * override this behavior by setting the MK_MESSAGE bit in the SCB 14788c2ecf20Sopenharmony_ci * control byte. This will cause us to interrupt the host and allow 14798c2ecf20Sopenharmony_ci * it to handle the message phase completely on its own. If the bit 14808c2ecf20Sopenharmony_ci * associated with this target is set, we will also interrupt the host, 14818c2ecf20Sopenharmony_ci * thereby allowing it to send a message on the next selection regardless 14828c2ecf20Sopenharmony_ci * of the transaction being sent. 14838c2ecf20Sopenharmony_ci * 14848c2ecf20Sopenharmony_ci * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. 14858c2ecf20Sopenharmony_ci * This is done to allow the host to send messages outside of an identify 14868c2ecf20Sopenharmony_ci * sequence while protecting the seqencer from testing the MK_MESSAGE bit 14878c2ecf20Sopenharmony_ci * on an SCB that might not be for the current nexus. (For example, a 14888c2ecf20Sopenharmony_ci * BDR message in response to a bad reselection would leave us pointed to 14898c2ecf20Sopenharmony_ci * an SCB that doesn't have anything to do with the current target). 14908c2ecf20Sopenharmony_ci * 14918c2ecf20Sopenharmony_ci * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, 14928c2ecf20Sopenharmony_ci * bus device reset). 14938c2ecf20Sopenharmony_ci * 14948c2ecf20Sopenharmony_ci * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, 14958c2ecf20Sopenharmony_ci * in case the target decides to put us in this phase for some strange 14968c2ecf20Sopenharmony_ci * reason. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_cip_mesgout_retry: 14998c2ecf20Sopenharmony_ci /* Turn on ATN for the retry */ 15008c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 15018c2ecf20Sopenharmony_ci or SCSISIGO, ATNO, LASTPHASE; 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci mvi SCSISIGO, ATNO; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_cip_mesgout: 15068c2ecf20Sopenharmony_ci mov SINDEX, MSG_OUT; 15078c2ecf20Sopenharmony_ci cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; 15088c2ecf20Sopenharmony_ci test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; 15098c2ecf20Sopenharmony_cip_mesgout_identify: 15108c2ecf20Sopenharmony_ci or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN; 15118c2ecf20Sopenharmony_ci test SCB_CONTROL, DISCENB jnz . + 2; 15128c2ecf20Sopenharmony_ci and SINDEX, ~DISCENB; 15138c2ecf20Sopenharmony_ci/* 15148c2ecf20Sopenharmony_ci * Send a tag message if TAG_ENB is set in the SCB control block. 15158c2ecf20Sopenharmony_ci * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_cip_mesgout_tag: 15188c2ecf20Sopenharmony_ci test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; 15198c2ecf20Sopenharmony_ci mov SCSIDATL, SINDEX; /* Send the identify message */ 15208c2ecf20Sopenharmony_ci call phase_lock; 15218c2ecf20Sopenharmony_ci cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 15228c2ecf20Sopenharmony_ci and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; 15238c2ecf20Sopenharmony_ci call phase_lock; 15248c2ecf20Sopenharmony_ci cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; 15258c2ecf20Sopenharmony_ci mov SCB_TAG jmp p_mesgout_onebyte; 15268c2ecf20Sopenharmony_ci/* 15278c2ecf20Sopenharmony_ci * Interrupt the driver, and allow it to handle this message 15288c2ecf20Sopenharmony_ci * phase and any required retries. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_cip_mesgout_from_host: 15318c2ecf20Sopenharmony_ci cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; 15328c2ecf20Sopenharmony_ci jmp host_message_loop; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cip_mesgout_onebyte: 15358c2ecf20Sopenharmony_ci mvi CLRSINT1, CLRATNO; 15368c2ecf20Sopenharmony_ci mov SCSIDATL, SINDEX; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci/* 15398c2ecf20Sopenharmony_ci * If the next bus phase after ATN drops is message out, it means 15408c2ecf20Sopenharmony_ci * that the target is requesting that the last message(s) be resent. 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_ci call phase_lock; 15438c2ecf20Sopenharmony_ci cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cip_mesgout_done: 15468c2ecf20Sopenharmony_ci mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ 15478c2ecf20Sopenharmony_ci mov LAST_MSG, MSG_OUT; 15488c2ecf20Sopenharmony_ci mvi MSG_OUT, MSG_NOOP; /* No message left */ 15498c2ecf20Sopenharmony_ci jmp ITloop; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci/* 15528c2ecf20Sopenharmony_ci * Message in phase. Bytes are read using Automatic PIO mode. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_cip_mesgin: 15558c2ecf20Sopenharmony_ci mvi ACCUM call inb_first; /* read the 1st message byte */ 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci test A,MSG_IDENTIFYFLAG jnz mesgin_identify; 15588c2ecf20Sopenharmony_ci cmp A,MSG_DISCONNECT je mesgin_disconnect; 15598c2ecf20Sopenharmony_ci cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; 15608c2ecf20Sopenharmony_ci cmp ALLZEROS,A je mesgin_complete; 15618c2ecf20Sopenharmony_ci cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; 15628c2ecf20Sopenharmony_ci cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; 15638c2ecf20Sopenharmony_ci cmp A,MSG_NOOP je mesgin_done; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/* 15668c2ecf20Sopenharmony_ci * Pushed message loop to allow the kernel to 15678c2ecf20Sopenharmony_ci * run it's own message state engine. To avoid an 15688c2ecf20Sopenharmony_ci * extra nop instruction after signaling the kernel, 15698c2ecf20Sopenharmony_ci * we perform the phase_lock before checking to see 15708c2ecf20Sopenharmony_ci * if we should exit the loop and skip the phase_lock 15718c2ecf20Sopenharmony_ci * in the ITloop. Performing back to back phase_locks 15728c2ecf20Sopenharmony_ci * shouldn't hurt, but why do it twice... 15738c2ecf20Sopenharmony_ci */ 15748c2ecf20Sopenharmony_cihost_message_loop: 15758c2ecf20Sopenharmony_ci mvi HOST_MSG_LOOP call set_seqint; 15768c2ecf20Sopenharmony_ci call phase_lock; 15778c2ecf20Sopenharmony_ci cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; 15788c2ecf20Sopenharmony_ci jmp host_message_loop; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_cimesgin_ign_wide_residue: 15818c2ecf20Sopenharmony_ciif ((ahc->features & AHC_WIDE) != 0) { 15828c2ecf20Sopenharmony_ci test SCSIRATE, WIDEXFER jz mesgin_reject; 15838c2ecf20Sopenharmony_ci /* Pull the residue byte */ 15848c2ecf20Sopenharmony_ci mvi ARG_1 call inb_next; 15858c2ecf20Sopenharmony_ci cmp ARG_1, 0x01 jne mesgin_reject; 15868c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; 15878c2ecf20Sopenharmony_ci test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done; 15888c2ecf20Sopenharmony_ci mvi IGN_WIDE_RES call set_seqint; 15898c2ecf20Sopenharmony_ci jmp mesgin_done; 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_cimesgin_proto_violation: 15938c2ecf20Sopenharmony_ci mvi PROTO_VIOLATION call set_seqint; 15948c2ecf20Sopenharmony_ci jmp mesgin_done; 15958c2ecf20Sopenharmony_cimesgin_reject: 15968c2ecf20Sopenharmony_ci mvi MSG_MESSAGE_REJECT call mk_mesg; 15978c2ecf20Sopenharmony_cimesgin_done: 15988c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 15998c2ecf20Sopenharmony_ci jmp ITloop; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci/* 16028c2ecf20Sopenharmony_ci * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, 16038c2ecf20Sopenharmony_ci * and trigger a completion interrupt. Before doing so, check to see if there 16048c2ecf20Sopenharmony_ci * is a residual or the status byte is something other than STATUS_GOOD (0). 16058c2ecf20Sopenharmony_ci * In either of these conditions, we upload the SCB back to the host so it can 16068c2ecf20Sopenharmony_ci * process this information. In the case of a non zero status byte, we 16078c2ecf20Sopenharmony_ci * additionally interrupt the kernel driver synchronously, allowing it to 16088c2ecf20Sopenharmony_ci * decide if sense should be retrieved. If the kernel driver wishes to request 16098c2ecf20Sopenharmony_ci * sense, it will fill the kernel SCB with a request sense command, requeue 16108c2ecf20Sopenharmony_ci * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 16118c2ecf20Sopenharmony_ci * RETURN_1 to SEND_SENSE. 16128c2ecf20Sopenharmony_ci */ 16138c2ecf20Sopenharmony_cimesgin_complete: 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci /* 16168c2ecf20Sopenharmony_ci * If ATN is raised, we still want to give the target a message. 16178c2ecf20Sopenharmony_ci * Perhaps there was a parity error on this last message byte. 16188c2ecf20Sopenharmony_ci * Either way, the target should take us to message out phase 16198c2ecf20Sopenharmony_ci * and then attempt to complete the command again. We should use a 16208c2ecf20Sopenharmony_ci * critical section here to guard against a timeout triggering 16218c2ecf20Sopenharmony_ci * for this command and setting ATN while we are still processing 16228c2ecf20Sopenharmony_ci * the completion. 16238c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jnz mesgin_done; 16248c2ecf20Sopenharmony_ci */ 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci /* 16278c2ecf20Sopenharmony_ci * If we are identified and have successfully sent the CDB, 16288c2ecf20Sopenharmony_ci * any status will do. Optimize this fast path. 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ci test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; 16318c2ecf20Sopenharmony_ci test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci /* 16348c2ecf20Sopenharmony_ci * If the target never sent an identify message but instead went 16358c2ecf20Sopenharmony_ci * to mesgin to give an invalid message, let the host abort us. 16368c2ecf20Sopenharmony_ci */ 16378c2ecf20Sopenharmony_ci test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* 16408c2ecf20Sopenharmony_ci * If we recevied good status but never successfully sent the 16418c2ecf20Sopenharmony_ci * cdb, abort the command. 16428c2ecf20Sopenharmony_ci */ 16438c2ecf20Sopenharmony_ci test SCB_SCSI_STATUS,0xff jnz complete_accepted; 16448c2ecf20Sopenharmony_ci test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_cicomplete_accepted: 16478c2ecf20Sopenharmony_ci /* 16488c2ecf20Sopenharmony_ci * See if we attempted to deliver a message but the target ingnored us. 16498c2ecf20Sopenharmony_ci */ 16508c2ecf20Sopenharmony_ci test SCB_CONTROL, MK_MESSAGE jz . + 2; 16518c2ecf20Sopenharmony_ci mvi MKMSG_FAILED call set_seqint; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci /* 16548c2ecf20Sopenharmony_ci * Check for residuals 16558c2ecf20Sopenharmony_ci */ 16568c2ecf20Sopenharmony_ci test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ 16578c2ecf20Sopenharmony_ci test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ 16588c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; 16598c2ecf20Sopenharmony_cicheck_status: 16608c2ecf20Sopenharmony_ci test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ 16618c2ecf20Sopenharmony_ciupload_scb: 16628c2ecf20Sopenharmony_ci or SCB_SGPTR, SG_RESID_VALID; 16638c2ecf20Sopenharmony_ci mvi DMAPARAMS, FIFORESET; 16648c2ecf20Sopenharmony_ci mov SCB_TAG call dma_scb; 16658c2ecf20Sopenharmony_ci test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ 16668c2ecf20Sopenharmony_ci mvi BAD_STATUS call set_seqint; /* let driver know */ 16678c2ecf20Sopenharmony_ci cmp RETURN_1, SEND_SENSE jne complete; 16688c2ecf20Sopenharmony_ci call add_scb_to_free_list; 16698c2ecf20Sopenharmony_ci jmp await_busfree; 16708c2ecf20Sopenharmony_cicomplete: 16718c2ecf20Sopenharmony_ci mov SCB_TAG call complete_post; 16728c2ecf20Sopenharmony_ci jmp await_busfree; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cicomplete_post: 16768c2ecf20Sopenharmony_ci /* Post the SCBID in SINDEX and issue an interrupt */ 16778c2ecf20Sopenharmony_ci call add_scb_to_free_list; 16788c2ecf20Sopenharmony_ci mov ARG_1, SINDEX; 16798c2ecf20Sopenharmony_ci if ((ahc->features & AHC_QUEUE_REGS) != 0) { 16808c2ecf20Sopenharmony_ci mov A, SDSCB_QOFF; 16818c2ecf20Sopenharmony_ci } else { 16828c2ecf20Sopenharmony_ci mov A, QOUTPOS; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci mvi QOUTFIFO_OFFSET call post_byte_setup; 16858c2ecf20Sopenharmony_ci mov ARG_1 call post_byte; 16868c2ecf20Sopenharmony_ci if ((ahc->features & AHC_QUEUE_REGS) == 0) { 16878c2ecf20Sopenharmony_ci inc QOUTPOS; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci mvi INTSTAT,CMDCMPLT ret; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_INITIATORROLE) != 0) { 16928c2ecf20Sopenharmony_ci/* 16938c2ecf20Sopenharmony_ci * Is it a disconnect message? Set a flag in the SCB to remind us 16948c2ecf20Sopenharmony_ci * and await the bus going free. If this is an untagged transaction 16958c2ecf20Sopenharmony_ci * store the SCB id for it in our untagged target table for lookup on 16968c2ecf20Sopenharmony_ci * a reselection. 16978c2ecf20Sopenharmony_ci */ 16988c2ecf20Sopenharmony_cimesgin_disconnect: 16998c2ecf20Sopenharmony_ci /* 17008c2ecf20Sopenharmony_ci * If ATN is raised, we still want to give the target a message. 17018c2ecf20Sopenharmony_ci * Perhaps there was a parity error on this last message byte 17028c2ecf20Sopenharmony_ci * or we want to abort this command. Either way, the target 17038c2ecf20Sopenharmony_ci * should take us to message out phase and then attempt to 17048c2ecf20Sopenharmony_ci * disconnect again. 17058c2ecf20Sopenharmony_ci * XXX - Wait for more testing. 17068c2ecf20Sopenharmony_ci test SCSISIGI, ATNI jnz mesgin_done; 17078c2ecf20Sopenharmony_ci */ 17088c2ecf20Sopenharmony_ci test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT 17098c2ecf20Sopenharmony_ci jnz mesgin_proto_violation; 17108c2ecf20Sopenharmony_ci or SCB_CONTROL,DISCONNECTED; 17118c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 17128c2ecf20Sopenharmony_ci call add_scb_to_disc_list; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci test SCB_CONTROL, TAG_ENB jnz await_busfree; 17158c2ecf20Sopenharmony_ci mov ARG_1, SCB_TAG; 17168c2ecf20Sopenharmony_ci and SAVED_LUN, LID, SCB_LUN; 17178c2ecf20Sopenharmony_ci mov SCB_SCSIID call set_busy_target; 17188c2ecf20Sopenharmony_ci jmp await_busfree; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci/* 17218c2ecf20Sopenharmony_ci * Save data pointers message: 17228c2ecf20Sopenharmony_ci * Copying RAM values back to SCB, for Save Data Pointers message, but 17238c2ecf20Sopenharmony_ci * only if we've actually been into a data phase to change them. This 17248c2ecf20Sopenharmony_ci * protects against bogus data in scratch ram and the residual counts 17258c2ecf20Sopenharmony_ci * since they are only initialized when we go into data_in or data_out. 17268c2ecf20Sopenharmony_ci * Ack the message as soon as possible. For chips without S/G pipelining, 17278c2ecf20Sopenharmony_ci * we can only ack the message after SHADDR has been saved. On these 17288c2ecf20Sopenharmony_ci * chips, SHADDR increments with every bus transaction, even PIO. 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_cimesgin_sdptrs: 17318c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 17328c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 17338c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE jz ITloop; 17348c2ecf20Sopenharmony_ci } else { 17358c2ecf20Sopenharmony_ci test SEQ_FLAGS, DPHASE jz mesgin_done; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci /* 17398c2ecf20Sopenharmony_ci * If we are asked to save our position at the end of the 17408c2ecf20Sopenharmony_ci * transfer, just mark us at the end rather than perform a 17418c2ecf20Sopenharmony_ci * full save. 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full; 17448c2ecf20Sopenharmony_ci or SCB_SGPTR, SG_LIST_NULL; 17458c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) != 0) { 17468c2ecf20Sopenharmony_ci jmp ITloop; 17478c2ecf20Sopenharmony_ci } else { 17488c2ecf20Sopenharmony_ci jmp mesgin_done; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cimesgin_sdptrs_full: 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci /* 17548c2ecf20Sopenharmony_ci * The SCB_SGPTR becomes the next one we'll download, 17558c2ecf20Sopenharmony_ci * and the SCB_DATAPTR becomes the current SHADDR. 17568c2ecf20Sopenharmony_ci * Use the residual number since STCNT is corrupted by 17578c2ecf20Sopenharmony_ci * any message transfer. 17588c2ecf20Sopenharmony_ci */ 17598c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 17608c2ecf20Sopenharmony_ci bmov SCB_DATAPTR, SHADDR, 4; 17618c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) == 0) { 17628c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; 17658c2ecf20Sopenharmony_ci } else { 17668c2ecf20Sopenharmony_ci mvi DINDEX, SCB_DATAPTR; 17678c2ecf20Sopenharmony_ci mvi SHADDR call bcopy_4; 17688c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 17698c2ecf20Sopenharmony_ci mvi SCB_RESIDUAL_DATACNT call bcopy_8; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci jmp ITloop; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci/* 17748c2ecf20Sopenharmony_ci * Restore pointers message? Data pointers are recopied from the 17758c2ecf20Sopenharmony_ci * SCB anytime we enter a data phase for the first time, so all 17768c2ecf20Sopenharmony_ci * we need to do is clear the DPHASE flag and let the data phase 17778c2ecf20Sopenharmony_ci * code do the rest. We also reset/reallocate the FIFO to make 17788c2ecf20Sopenharmony_ci * sure we have a clean start for the next data or command phase. 17798c2ecf20Sopenharmony_ci */ 17808c2ecf20Sopenharmony_cimesgin_rdptrs: 17818c2ecf20Sopenharmony_ci and SEQ_FLAGS, ~DPHASE; /* 17828c2ecf20Sopenharmony_ci * We'll reload them 17838c2ecf20Sopenharmony_ci * the next time through 17848c2ecf20Sopenharmony_ci * the dataphase. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci or SXFRCTL0, CLRSTCNT|CLRCHN; 17878c2ecf20Sopenharmony_ci jmp mesgin_done; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci/* 17908c2ecf20Sopenharmony_ci * Index into our Busy Target table. SINDEX and DINDEX are modified 17918c2ecf20Sopenharmony_ci * upon return. SCBPTR may be modified by this action. 17928c2ecf20Sopenharmony_ci */ 17938c2ecf20Sopenharmony_ciset_busy_target: 17948c2ecf20Sopenharmony_ci shr DINDEX, 4, SINDEX; 17958c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 17968c2ecf20Sopenharmony_ci mov SCBPTR, SAVED_LUN; 17978c2ecf20Sopenharmony_ci add DINDEX, SCB_64_BTT; 17988c2ecf20Sopenharmony_ci } else { 17998c2ecf20Sopenharmony_ci add DINDEX, BUSY_TARGETS; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci mov DINDIR, ARG_1 ret; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci/* 18048c2ecf20Sopenharmony_ci * Identify message? For a reconnecting target, this tells us the lun 18058c2ecf20Sopenharmony_ci * that the reconnection is for - find the correct SCB and switch to it, 18068c2ecf20Sopenharmony_ci * clearing the "disconnected" bit so we don't "find" it by accident later. 18078c2ecf20Sopenharmony_ci */ 18088c2ecf20Sopenharmony_cimesgin_identify: 18098c2ecf20Sopenharmony_ci /* 18108c2ecf20Sopenharmony_ci * Determine whether a target is using tagged or non-tagged 18118c2ecf20Sopenharmony_ci * transactions by first looking at the transaction stored in 18128c2ecf20Sopenharmony_ci * the busy target array. If there is no untagged transaction 18138c2ecf20Sopenharmony_ci * for this target or the transaction is for a different lun, then 18148c2ecf20Sopenharmony_ci * this must be a tagged transaction. 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_ci shr SINDEX, 4, SAVED_SCSIID; 18178c2ecf20Sopenharmony_ci and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; 18188c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 18198c2ecf20Sopenharmony_ci add SINDEX, SCB_64_BTT; 18208c2ecf20Sopenharmony_ci mov SCBPTR, SAVED_LUN; 18218c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 18228c2ecf20Sopenharmony_ci add NONE, -SCB_64_BTT, SINDEX; 18238c2ecf20Sopenharmony_ci jc . + 2; 18248c2ecf20Sopenharmony_ci mvi INTSTAT, OUT_OF_RANGE; 18258c2ecf20Sopenharmony_ci nop; 18268c2ecf20Sopenharmony_ci add NONE, -(SCB_64_BTT + 16), SINDEX; 18278c2ecf20Sopenharmony_ci jnc . + 2; 18288c2ecf20Sopenharmony_ci mvi INTSTAT, OUT_OF_RANGE; 18298c2ecf20Sopenharmony_ci nop; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci } else { 18328c2ecf20Sopenharmony_ci add SINDEX, BUSY_TARGETS; 18338c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 18348c2ecf20Sopenharmony_ci add NONE, -BUSY_TARGETS, SINDEX; 18358c2ecf20Sopenharmony_ci jc . + 2; 18368c2ecf20Sopenharmony_ci mvi INTSTAT, OUT_OF_RANGE; 18378c2ecf20Sopenharmony_ci nop; 18388c2ecf20Sopenharmony_ci add NONE, -(BUSY_TARGETS + 16), SINDEX; 18398c2ecf20Sopenharmony_ci jnc . + 2; 18408c2ecf20Sopenharmony_ci mvi INTSTAT, OUT_OF_RANGE; 18418c2ecf20Sopenharmony_ci nop; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci mov ARG_1, SINDIR; 18458c2ecf20Sopenharmony_ci cmp ARG_1, SCB_LIST_NULL je snoop_tag; 18468c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 18478c2ecf20Sopenharmony_ci mov ARG_1 call findSCB; 18488c2ecf20Sopenharmony_ci } else { 18498c2ecf20Sopenharmony_ci mov SCBPTR, ARG_1; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 18528c2ecf20Sopenharmony_ci jmp setup_SCB_id_lun_okay; 18538c2ecf20Sopenharmony_ci } else { 18548c2ecf20Sopenharmony_ci /* 18558c2ecf20Sopenharmony_ci * We only allow one untagged command per-target 18568c2ecf20Sopenharmony_ci * at a time. So, if the lun doesn't match, look 18578c2ecf20Sopenharmony_ci * for a tag message. 18588c2ecf20Sopenharmony_ci */ 18598c2ecf20Sopenharmony_ci and A, LID, SCB_LUN; 18608c2ecf20Sopenharmony_ci cmp SAVED_LUN, A je setup_SCB_id_lun_okay; 18618c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 18628c2ecf20Sopenharmony_ci /* 18638c2ecf20Sopenharmony_ci * findSCB removes the SCB from the 18648c2ecf20Sopenharmony_ci * disconnected list, so we must replace 18658c2ecf20Sopenharmony_ci * it there should this SCB be for another 18668c2ecf20Sopenharmony_ci * lun. 18678c2ecf20Sopenharmony_ci */ 18688c2ecf20Sopenharmony_ci call cleanup_scb; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci/* 18738c2ecf20Sopenharmony_ci * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. 18748c2ecf20Sopenharmony_ci * If we get one, we use the tag returned to find the proper 18758c2ecf20Sopenharmony_ci * SCB. With SCB paging, we must search for non-tagged 18768c2ecf20Sopenharmony_ci * transactions since the SCB may exist in any slot. If we're not 18778c2ecf20Sopenharmony_ci * using SCB paging, we can use the tag as the direct index to the 18788c2ecf20Sopenharmony_ci * SCB. 18798c2ecf20Sopenharmony_ci */ 18808c2ecf20Sopenharmony_cisnoop_tag: 18818c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 18828c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x80; 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /* ACK Identify MSG */ 18858c2ecf20Sopenharmony_ci call phase_lock; 18868c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 18878c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x1; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci cmp LASTPHASE, P_MESGIN jne not_found; 18908c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 18918c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x2; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; 18948c2ecf20Sopenharmony_ciget_tag: 18958c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 18968c2ecf20Sopenharmony_ci mvi ARG_1 call inb_next; /* tag value */ 18978c2ecf20Sopenharmony_ci mov ARG_1 call findSCB; 18988c2ecf20Sopenharmony_ci } else { 18998c2ecf20Sopenharmony_ci mvi ARG_1 call inb_next; /* tag value */ 19008c2ecf20Sopenharmony_ci mov SCBPTR, ARG_1; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci/* 19048c2ecf20Sopenharmony_ci * Ensure that the SCB the tag points to is for 19058c2ecf20Sopenharmony_ci * an SCB transaction to the reconnecting target. 19068c2ecf20Sopenharmony_ci */ 19078c2ecf20Sopenharmony_cisetup_SCB: 19088c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 19098c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x4; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci mov A, SCB_SCSIID; 19128c2ecf20Sopenharmony_ci cmp SAVED_SCSIID, A jne not_found_cleanup_scb; 19138c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 19148c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x8; 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_cisetup_SCB_id_okay: 19178c2ecf20Sopenharmony_ci and A, LID, SCB_LUN; 19188c2ecf20Sopenharmony_ci cmp SAVED_LUN, A jne not_found_cleanup_scb; 19198c2ecf20Sopenharmony_cisetup_SCB_id_lun_okay: 19208c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { 19218c2ecf20Sopenharmony_ci or SEQ_FLAGS, 0x10; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; 19248c2ecf20Sopenharmony_ci and SCB_CONTROL,~DISCONNECTED; 19258c2ecf20Sopenharmony_ci test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; 19268c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 19278c2ecf20Sopenharmony_ci mov A, SCBPTR; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci mvi ARG_1, SCB_LIST_NULL; 19308c2ecf20Sopenharmony_ci mov SAVED_SCSIID call set_busy_target; 19318c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 19328c2ecf20Sopenharmony_ci mov SCBPTR, A; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_cisetup_SCB_tagged: 19358c2ecf20Sopenharmony_ci clr SEQ_FLAGS; /* make note of IDENTIFY */ 19368c2ecf20Sopenharmony_ci call set_transfer_settings; 19378c2ecf20Sopenharmony_ci /* See if the host wants to send a message upon reconnection */ 19388c2ecf20Sopenharmony_ci test SCB_CONTROL, MK_MESSAGE jz mesgin_done; 19398c2ecf20Sopenharmony_ci mvi HOST_MSG call mk_mesg; 19408c2ecf20Sopenharmony_ci jmp mesgin_done; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cinot_found_cleanup_scb: 19438c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 19448c2ecf20Sopenharmony_ci call cleanup_scb; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_cinot_found: 19478c2ecf20Sopenharmony_ci mvi NO_MATCH call set_seqint; 19488c2ecf20Sopenharmony_ci jmp mesgin_done; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cimk_mesg: 19518c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 19528c2ecf20Sopenharmony_ci or SCSISIGO, ATNO, LASTPHASE; 19538c2ecf20Sopenharmony_ci } else { 19548c2ecf20Sopenharmony_ci mvi SCSISIGO, ATNO; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci mov MSG_OUT,SINDEX ret; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci/* 19598c2ecf20Sopenharmony_ci * Functions to read data in Automatic PIO mode. 19608c2ecf20Sopenharmony_ci * 19618c2ecf20Sopenharmony_ci * According to Adaptec's documentation, an ACK is not sent on input from 19628c2ecf20Sopenharmony_ci * the target until SCSIDATL is read from. So we wait until SCSIDATL is 19638c2ecf20Sopenharmony_ci * latched (the usual way), then read the data byte directly off the bus 19648c2ecf20Sopenharmony_ci * using SCSIBUSL. When we have pulled the ATN line, or we just want to 19658c2ecf20Sopenharmony_ci * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI 19668c2ecf20Sopenharmony_ci * spec guarantees that the target will hold the data byte on the bus until 19678c2ecf20Sopenharmony_ci * we send our ACK. 19688c2ecf20Sopenharmony_ci * 19698c2ecf20Sopenharmony_ci * The assumption here is that these are called in a particular sequence, 19708c2ecf20Sopenharmony_ci * and that REQ is already set when inb_first is called. inb_{first,next} 19718c2ecf20Sopenharmony_ci * use the same calling convention as inb. 19728c2ecf20Sopenharmony_ci */ 19738c2ecf20Sopenharmony_ciinb_next_wait_perr: 19748c2ecf20Sopenharmony_ci mvi PERR_DETECTED call set_seqint; 19758c2ecf20Sopenharmony_ci jmp inb_next_wait; 19768c2ecf20Sopenharmony_ciinb_next: 19778c2ecf20Sopenharmony_ci mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ 19788c2ecf20Sopenharmony_ciinb_next_wait: 19798c2ecf20Sopenharmony_ci /* 19808c2ecf20Sopenharmony_ci * If there is a parity error, wait for the kernel to 19818c2ecf20Sopenharmony_ci * see the interrupt and prepare our message response 19828c2ecf20Sopenharmony_ci * before continuing. 19838c2ecf20Sopenharmony_ci */ 19848c2ecf20Sopenharmony_ci test SSTAT1, REQINIT jz inb_next_wait; 19858c2ecf20Sopenharmony_ci test SSTAT1, SCSIPERR jnz inb_next_wait_perr; 19868c2ecf20Sopenharmony_ciinb_next_check_phase: 19878c2ecf20Sopenharmony_ci and LASTPHASE, PHASE_MASK, SCSISIGI; 19888c2ecf20Sopenharmony_ci cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; 19898c2ecf20Sopenharmony_ciinb_first: 19908c2ecf20Sopenharmony_ci mov DINDEX,SINDEX; 19918c2ecf20Sopenharmony_ci mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ 19928c2ecf20Sopenharmony_ciinb_last: 19938c2ecf20Sopenharmony_ci mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ 19948c2ecf20Sopenharmony_ci} 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_TARGETROLE) != 0) { 19978c2ecf20Sopenharmony_ci/* 19988c2ecf20Sopenharmony_ci * Change to a new phase. If we are changing the state of the I/O signal, 19998c2ecf20Sopenharmony_ci * from out to in, wait an additional data release delay before continuing. 20008c2ecf20Sopenharmony_ci */ 20018c2ecf20Sopenharmony_cichange_phase: 20028c2ecf20Sopenharmony_ci /* Wait for preceding I/O session to complete. */ 20038c2ecf20Sopenharmony_ci test SCSISIGI, ACKI jnz .; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci /* Change the phase */ 20068c2ecf20Sopenharmony_ci and DINDEX, IOI, SCSISIGI; 20078c2ecf20Sopenharmony_ci mov SCSISIGO, SINDEX; 20088c2ecf20Sopenharmony_ci and A, IOI, SINDEX; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci /* 20118c2ecf20Sopenharmony_ci * If the data direction has changed, from 20128c2ecf20Sopenharmony_ci * out (initiator driving) to in (target driving), 20138c2ecf20Sopenharmony_ci * we must wait at least a data release delay plus 20148c2ecf20Sopenharmony_ci * the normal bus settle delay. [SCSI III SPI 10.11.0] 20158c2ecf20Sopenharmony_ci */ 20168c2ecf20Sopenharmony_ci cmp DINDEX, A je change_phase_wait; 20178c2ecf20Sopenharmony_ci test SINDEX, IOI jz change_phase_wait; 20188c2ecf20Sopenharmony_ci call change_phase_wait; 20198c2ecf20Sopenharmony_cichange_phase_wait: 20208c2ecf20Sopenharmony_ci nop; 20218c2ecf20Sopenharmony_ci nop; 20228c2ecf20Sopenharmony_ci nop; 20238c2ecf20Sopenharmony_ci nop ret; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci/* 20268c2ecf20Sopenharmony_ci * Send a byte to an initiator in Automatic PIO mode. 20278c2ecf20Sopenharmony_ci */ 20288c2ecf20Sopenharmony_citarget_outb: 20298c2ecf20Sopenharmony_ci or SXFRCTL0, SPIOEN; 20308c2ecf20Sopenharmony_ci test SSTAT0, SPIORDY jz .; 20318c2ecf20Sopenharmony_ci mov SCSIDATL, SINDEX; 20328c2ecf20Sopenharmony_ci test SSTAT0, SPIORDY jz .; 20338c2ecf20Sopenharmony_ci and SXFRCTL0, ~SPIOEN ret; 20348c2ecf20Sopenharmony_ci} 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci/* 20378c2ecf20Sopenharmony_ci * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will 20388c2ecf20Sopenharmony_ci * be set to the position of the SCB. If the SCB cannot be found locally, 20398c2ecf20Sopenharmony_ci * it will be paged in from host memory. RETURN_2 stores the address of the 20408c2ecf20Sopenharmony_ci * preceding SCB in the disconnected list which can be used to speed up 20418c2ecf20Sopenharmony_ci * removal of the found SCB from the disconnected list. 20428c2ecf20Sopenharmony_ci */ 20438c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_PAGESCBS) != 0) { 20448c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 20458c2ecf20Sopenharmony_cifindSCB: 20468c2ecf20Sopenharmony_ci mov A, SINDEX; /* Tag passed in SINDEX */ 20478c2ecf20Sopenharmony_ci cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; 20488c2ecf20Sopenharmony_ci mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ 20498c2ecf20Sopenharmony_ci mvi ARG_2, SCB_LIST_NULL; /* Head of list */ 20508c2ecf20Sopenharmony_ci jmp findSCB_loop; 20518c2ecf20Sopenharmony_cifindSCB_next: 20528c2ecf20Sopenharmony_ci cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; 20538c2ecf20Sopenharmony_ci mov ARG_2, SCBPTR; 20548c2ecf20Sopenharmony_ci mov SCBPTR,SCB_NEXT; 20558c2ecf20Sopenharmony_cifindSCB_loop: 20568c2ecf20Sopenharmony_ci cmp SCB_TAG, A jne findSCB_next; 20578c2ecf20Sopenharmony_cirem_scb_from_disc_list: 20588c2ecf20Sopenharmony_ci cmp ARG_2, SCB_LIST_NULL je rHead; 20598c2ecf20Sopenharmony_ci mov DINDEX, SCB_NEXT; 20608c2ecf20Sopenharmony_ci mov SINDEX, SCBPTR; 20618c2ecf20Sopenharmony_ci mov SCBPTR, ARG_2; 20628c2ecf20Sopenharmony_ci mov SCB_NEXT, DINDEX; 20638c2ecf20Sopenharmony_ci mov SCBPTR, SINDEX ret; 20648c2ecf20Sopenharmony_cirHead: 20658c2ecf20Sopenharmony_ci mov DISCONNECTED_SCBH,SCB_NEXT ret; 20668c2ecf20Sopenharmony_ciEND_CRITICAL; 20678c2ecf20Sopenharmony_cifindSCB_notFound: 20688c2ecf20Sopenharmony_ci /* 20698c2ecf20Sopenharmony_ci * We didn't find it. Page in the SCB. 20708c2ecf20Sopenharmony_ci */ 20718c2ecf20Sopenharmony_ci mov ARG_1, A; /* Save tag */ 20728c2ecf20Sopenharmony_ci mov ALLZEROS call get_free_or_disc_scb; 20738c2ecf20Sopenharmony_ci mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; 20748c2ecf20Sopenharmony_ci mov ARG_1 jmp dma_scb; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci/* 20788c2ecf20Sopenharmony_ci * Prepare the hardware to post a byte to host memory given an 20798c2ecf20Sopenharmony_ci * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_cipost_byte_setup: 20828c2ecf20Sopenharmony_ci mov ARG_2, SINDEX; 20838c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 20848c2ecf20Sopenharmony_ci mvi DINDEX, CCHADDR; 20858c2ecf20Sopenharmony_ci mvi SHARED_DATA_ADDR call set_1byte_addr; 20868c2ecf20Sopenharmony_ci mvi CCHCNT, 1; 20878c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCSCBRESET ret; 20888c2ecf20Sopenharmony_ci } else { 20898c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 20908c2ecf20Sopenharmony_ci mvi SHARED_DATA_ADDR call set_1byte_addr; 20918c2ecf20Sopenharmony_ci mvi 1 call set_hcnt; 20928c2ecf20Sopenharmony_ci mvi DFCNTRL, FIFORESET ret; 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cipost_byte: 20968c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 20978c2ecf20Sopenharmony_ci bmov CCSCBRAM, SINDEX, 1; 20988c2ecf20Sopenharmony_ci or CCSCBCTL, CCSCBEN|CCSCBRESET; 20998c2ecf20Sopenharmony_ci test CCSCBCTL, CCSCBDONE jz .; 21008c2ecf20Sopenharmony_ci clr CCSCBCTL ret; 21018c2ecf20Sopenharmony_ci } else { 21028c2ecf20Sopenharmony_ci mov DFDAT, SINDEX; 21038c2ecf20Sopenharmony_ci or DFCNTRL, HDMAEN|FIFOFLUSH; 21048c2ecf20Sopenharmony_ci jmp dma_finish; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ciphase_lock_perr: 21088c2ecf20Sopenharmony_ci mvi PERR_DETECTED call set_seqint; 21098c2ecf20Sopenharmony_ciphase_lock: 21108c2ecf20Sopenharmony_ci /* 21118c2ecf20Sopenharmony_ci * If there is a parity error, wait for the kernel to 21128c2ecf20Sopenharmony_ci * see the interrupt and prepare our message response 21138c2ecf20Sopenharmony_ci * before continuing. 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_ci test SSTAT1, REQINIT jz phase_lock; 21168c2ecf20Sopenharmony_ci test SSTAT1, SCSIPERR jnz phase_lock_perr; 21178c2ecf20Sopenharmony_ciphase_lock_latch_phase: 21188c2ecf20Sopenharmony_ci if ((ahc->features & AHC_DT) == 0) { 21198c2ecf20Sopenharmony_ci and SCSISIGO, PHASE_MASK, SCSISIGI; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci and LASTPHASE, PHASE_MASK, SCSISIGI ret; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ciif ((ahc->features & AHC_CMD_CHAN) == 0) { 21248c2ecf20Sopenharmony_ciset_hcnt: 21258c2ecf20Sopenharmony_ci mov HCNT[0], SINDEX; 21268c2ecf20Sopenharmony_ciclear_hcnt: 21278c2ecf20Sopenharmony_ci clr HCNT[1]; 21288c2ecf20Sopenharmony_ci clr HCNT[2] ret; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ciset_stcnt_from_hcnt: 21318c2ecf20Sopenharmony_ci mov STCNT[0], HCNT[0]; 21328c2ecf20Sopenharmony_ci mov STCNT[1], HCNT[1]; 21338c2ecf20Sopenharmony_ci mov STCNT[2], HCNT[2] ret; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_cibcopy_8: 21368c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21378c2ecf20Sopenharmony_cibcopy_7: 21388c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21398c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21408c2ecf20Sopenharmony_cibcopy_5: 21418c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21428c2ecf20Sopenharmony_cibcopy_4: 21438c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21448c2ecf20Sopenharmony_cibcopy_3: 21458c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21468c2ecf20Sopenharmony_ci mov DINDIR, SINDIR; 21478c2ecf20Sopenharmony_ci mov DINDIR, SINDIR ret; 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_TARGETROLE) != 0) { 21518c2ecf20Sopenharmony_ci/* 21528c2ecf20Sopenharmony_ci * Setup addr assuming that A is an index into 21538c2ecf20Sopenharmony_ci * an array of 32byte objects, SINDEX contains 21548c2ecf20Sopenharmony_ci * the base address of that array, and DINDEX 21558c2ecf20Sopenharmony_ci * contains the base address of the location 21568c2ecf20Sopenharmony_ci * to store the indexed address. 21578c2ecf20Sopenharmony_ci */ 21588c2ecf20Sopenharmony_ciset_32byte_addr: 21598c2ecf20Sopenharmony_ci shr ARG_2, 3, A; 21608c2ecf20Sopenharmony_ci shl A, 5; 21618c2ecf20Sopenharmony_ci jmp set_1byte_addr; 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci/* 21658c2ecf20Sopenharmony_ci * Setup addr assuming that A is an index into 21668c2ecf20Sopenharmony_ci * an array of 64byte objects, SINDEX contains 21678c2ecf20Sopenharmony_ci * the base address of that array, and DINDEX 21688c2ecf20Sopenharmony_ci * contains the base address of the location 21698c2ecf20Sopenharmony_ci * to store the indexed address. 21708c2ecf20Sopenharmony_ci */ 21718c2ecf20Sopenharmony_ciset_64byte_addr: 21728c2ecf20Sopenharmony_ci shr ARG_2, 2, A; 21738c2ecf20Sopenharmony_ci shl A, 6; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci/* 21768c2ecf20Sopenharmony_ci * Setup addr assuming that A + (ARG_2 * 256) is an 21778c2ecf20Sopenharmony_ci * index into an array of 1byte objects, SINDEX contains 21788c2ecf20Sopenharmony_ci * the base address of that array, and DINDEX contains 21798c2ecf20Sopenharmony_ci * the base address of the location to store the computed 21808c2ecf20Sopenharmony_ci * address. 21818c2ecf20Sopenharmony_ci */ 21828c2ecf20Sopenharmony_ciset_1byte_addr: 21838c2ecf20Sopenharmony_ci add DINDIR, A, SINDIR; 21848c2ecf20Sopenharmony_ci mov A, ARG_2; 21858c2ecf20Sopenharmony_ci adc DINDIR, A, SINDIR; 21868c2ecf20Sopenharmony_ci clr A; 21878c2ecf20Sopenharmony_ci adc DINDIR, A, SINDIR; 21888c2ecf20Sopenharmony_ci adc DINDIR, A, SINDIR ret; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci/* 21918c2ecf20Sopenharmony_ci * Either post or fetch an SCB from host memory based on the 21928c2ecf20Sopenharmony_ci * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. 21938c2ecf20Sopenharmony_ci */ 21948c2ecf20Sopenharmony_cidma_scb: 21958c2ecf20Sopenharmony_ci mov A, SINDEX; 21968c2ecf20Sopenharmony_ci if ((ahc->features & AHC_CMD_CHAN) != 0) { 21978c2ecf20Sopenharmony_ci mvi DINDEX, CCHADDR; 21988c2ecf20Sopenharmony_ci mvi HSCB_ADDR call set_64byte_addr; 21998c2ecf20Sopenharmony_ci mov CCSCBPTR, SCBPTR; 22008c2ecf20Sopenharmony_ci test DMAPARAMS, DIRECTION jz dma_scb_tohost; 22018c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_SCB_BTT) != 0) { 22028c2ecf20Sopenharmony_ci mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; 22038c2ecf20Sopenharmony_ci } else { 22048c2ecf20Sopenharmony_ci mvi CCHCNT, SCB_DOWNLOAD_SIZE; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; 22078c2ecf20Sopenharmony_ci cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; 22088c2ecf20Sopenharmony_ci jmp dma_scb_finish; 22098c2ecf20Sopenharmony_cidma_scb_tohost: 22108c2ecf20Sopenharmony_ci mvi CCHCNT, SCB_UPLOAD_SIZE; 22118c2ecf20Sopenharmony_ci if ((ahc->features & AHC_ULTRA2) == 0) { 22128c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCSCBRESET; 22138c2ecf20Sopenharmony_ci bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; 22148c2ecf20Sopenharmony_ci or CCSCBCTL, CCSCBEN|CCSCBRESET; 22158c2ecf20Sopenharmony_ci test CCSCBCTL, CCSCBDONE jz .; 22168c2ecf20Sopenharmony_ci } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { 22178c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCARREN|CCSCBRESET; 22188c2ecf20Sopenharmony_ci cmp CCSCBCTL, ARRDONE|CCARREN jne .; 22198c2ecf20Sopenharmony_ci mvi CCHCNT, SCB_UPLOAD_SIZE; 22208c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCSCBEN|CCSCBRESET; 22218c2ecf20Sopenharmony_ci cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; 22228c2ecf20Sopenharmony_ci } else { 22238c2ecf20Sopenharmony_ci mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; 22248c2ecf20Sopenharmony_ci cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_cidma_scb_finish: 22278c2ecf20Sopenharmony_ci clr CCSCBCTL; 22288c2ecf20Sopenharmony_ci test CCSCBCTL, CCARREN|CCSCBEN jnz .; 22298c2ecf20Sopenharmony_ci ret; 22308c2ecf20Sopenharmony_ci } else { 22318c2ecf20Sopenharmony_ci mvi DINDEX, HADDR; 22328c2ecf20Sopenharmony_ci mvi HSCB_ADDR call set_64byte_addr; 22338c2ecf20Sopenharmony_ci mvi SCB_DOWNLOAD_SIZE call set_hcnt; 22348c2ecf20Sopenharmony_ci mov DFCNTRL, DMAPARAMS; 22358c2ecf20Sopenharmony_ci test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; 22368c2ecf20Sopenharmony_ci /* Fill it with the SCB data */ 22378c2ecf20Sopenharmony_cicopy_scb_tofifo: 22388c2ecf20Sopenharmony_ci mvi SINDEX, SCB_BASE; 22398c2ecf20Sopenharmony_ci add A, SCB_DOWNLOAD_SIZE, SINDEX; 22408c2ecf20Sopenharmony_cicopy_scb_tofifo_loop: 22418c2ecf20Sopenharmony_ci call copy_to_fifo_8; 22428c2ecf20Sopenharmony_ci cmp SINDEX, A jne copy_scb_tofifo_loop; 22438c2ecf20Sopenharmony_ci or DFCNTRL, HDMAEN|FIFOFLUSH; 22448c2ecf20Sopenharmony_ci jmp dma_finish; 22458c2ecf20Sopenharmony_cidma_scb_fromhost: 22468c2ecf20Sopenharmony_ci mvi DINDEX, SCB_BASE; 22478c2ecf20Sopenharmony_ci if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { 22488c2ecf20Sopenharmony_ci /* 22498c2ecf20Sopenharmony_ci * The PCI module will only issue a PCI 22508c2ecf20Sopenharmony_ci * retry if the data FIFO is empty. If the 22518c2ecf20Sopenharmony_ci * host disconnects in the middle of a 22528c2ecf20Sopenharmony_ci * transfer, we must empty the fifo of all 22538c2ecf20Sopenharmony_ci * available data to force the chip to 22548c2ecf20Sopenharmony_ci * continue the transfer. This does not 22558c2ecf20Sopenharmony_ci * happen for SCSI transfers as the SCSI module 22568c2ecf20Sopenharmony_ci * will drain the FIFO as data are made available. 22578c2ecf20Sopenharmony_ci * When the hang occurs, we know that a multiple 22588c2ecf20Sopenharmony_ci * of 8 bytes is in the FIFO because the PCI 22598c2ecf20Sopenharmony_ci * module has an 8 byte input latch that only 22608c2ecf20Sopenharmony_ci * dumps to the FIFO when HCNT == 0 or the 22618c2ecf20Sopenharmony_ci * latch is full. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci clr A; 22648c2ecf20Sopenharmony_ci /* Wait for at least 8 bytes of data to arrive. */ 22658c2ecf20Sopenharmony_cidma_scb_hang_fifo: 22668c2ecf20Sopenharmony_ci test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; 22678c2ecf20Sopenharmony_cidma_scb_hang_wait: 22688c2ecf20Sopenharmony_ci test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; 22698c2ecf20Sopenharmony_ci test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 22708c2ecf20Sopenharmony_ci test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 22718c2ecf20Sopenharmony_ci test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; 22728c2ecf20Sopenharmony_ci /* 22738c2ecf20Sopenharmony_ci * The PCI module no longer intends to perform 22748c2ecf20Sopenharmony_ci * a PCI transaction. Drain the fifo. 22758c2ecf20Sopenharmony_ci */ 22768c2ecf20Sopenharmony_cidma_scb_hang_dma_drain_fifo: 22778c2ecf20Sopenharmony_ci not A, HCNT; 22788c2ecf20Sopenharmony_ci add A, SCB_DOWNLOAD_SIZE+SCB_BASE+1; 22798c2ecf20Sopenharmony_ci and A, ~0x7; 22808c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 22818c2ecf20Sopenharmony_ci cmp DINDEX, A jne . - 1; 22828c2ecf20Sopenharmony_ci cmp DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE 22838c2ecf20Sopenharmony_ci je dma_finish_nowait; 22848c2ecf20Sopenharmony_ci /* Restore A as the lines left to transfer. */ 22858c2ecf20Sopenharmony_ci add A, -SCB_BASE, DINDEX; 22868c2ecf20Sopenharmony_ci shr A, 3; 22878c2ecf20Sopenharmony_ci jmp dma_scb_hang_fifo; 22888c2ecf20Sopenharmony_cidma_scb_hang_dma_done: 22898c2ecf20Sopenharmony_ci and DFCNTRL, ~HDMAEN; 22908c2ecf20Sopenharmony_ci test DFCNTRL, HDMAEN jnz .; 22918c2ecf20Sopenharmony_ci add SEQADDR0, A; 22928c2ecf20Sopenharmony_ci } else { 22938c2ecf20Sopenharmony_ci call dma_finish; 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci call dfdat_in_8; 22968c2ecf20Sopenharmony_ci call dfdat_in_8; 22978c2ecf20Sopenharmony_ci call dfdat_in_8; 22988c2ecf20Sopenharmony_cidfdat_in_8: 22998c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23008c2ecf20Sopenharmony_cidfdat_in_7: 23018c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23028c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23038c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23048c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23058c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23068c2ecf20Sopenharmony_cidfdat_in_2: 23078c2ecf20Sopenharmony_ci mov DINDIR,DFDAT; 23088c2ecf20Sopenharmony_ci mov DINDIR,DFDAT ret; 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_cicopy_to_fifo_8: 23128c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23138c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23148c2ecf20Sopenharmony_cicopy_to_fifo_6: 23158c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23168c2ecf20Sopenharmony_cicopy_to_fifo_5: 23178c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23188c2ecf20Sopenharmony_cicopy_to_fifo_4: 23198c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23208c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23218c2ecf20Sopenharmony_ci mov DFDAT,SINDIR; 23228c2ecf20Sopenharmony_ci mov DFDAT,SINDIR ret; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci/* 23258c2ecf20Sopenharmony_ci * Wait for DMA from host memory to data FIFO to complete, then disable 23268c2ecf20Sopenharmony_ci * DMA and wait for it to acknowledge that it's off. 23278c2ecf20Sopenharmony_ci */ 23288c2ecf20Sopenharmony_cidma_finish: 23298c2ecf20Sopenharmony_ci test DFSTATUS,HDONE jz dma_finish; 23308c2ecf20Sopenharmony_cidma_finish_nowait: 23318c2ecf20Sopenharmony_ci /* Turn off DMA */ 23328c2ecf20Sopenharmony_ci and DFCNTRL, ~HDMAEN; 23338c2ecf20Sopenharmony_ci test DFCNTRL, HDMAEN jnz .; 23348c2ecf20Sopenharmony_ci ret; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci/* 23378c2ecf20Sopenharmony_ci * Restore an SCB that failed to match an incoming reselection 23388c2ecf20Sopenharmony_ci * to the correct/safe state. If the SCB is for a disconnected 23398c2ecf20Sopenharmony_ci * transaction, it must be returned to the disconnected list. 23408c2ecf20Sopenharmony_ci * If it is not in the disconnected state, it must be free. 23418c2ecf20Sopenharmony_ci */ 23428c2ecf20Sopenharmony_cicleanup_scb: 23438c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 23448c2ecf20Sopenharmony_ci test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ciadd_scb_to_free_list: 23478c2ecf20Sopenharmony_ci if ((ahc->flags & AHC_PAGESCBS) != 0) { 23488c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 23498c2ecf20Sopenharmony_ci mov SCB_NEXT, FREE_SCBH; 23508c2ecf20Sopenharmony_ci mvi SCB_TAG, SCB_LIST_NULL; 23518c2ecf20Sopenharmony_ci mov FREE_SCBH, SCBPTR ret; 23528c2ecf20Sopenharmony_ciEND_CRITICAL; 23538c2ecf20Sopenharmony_ci } else { 23548c2ecf20Sopenharmony_ci mvi SCB_TAG, SCB_LIST_NULL ret; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { 23588c2ecf20Sopenharmony_ciset_hhaddr: 23598c2ecf20Sopenharmony_ci or DSCOMMAND1, HADDLDSEL0; 23608c2ecf20Sopenharmony_ci and HADDR, SG_HIGH_ADDR_BITS, SINDEX; 23618c2ecf20Sopenharmony_ci and DSCOMMAND1, ~HADDLDSEL0 ret; 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ciif ((ahc->flags & AHC_PAGESCBS) != 0) { 23658c2ecf20Sopenharmony_ciget_free_or_disc_scb: 23668c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 23678c2ecf20Sopenharmony_ci cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; 23688c2ecf20Sopenharmony_ci cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; 23698c2ecf20Sopenharmony_cireturn_error: 23708c2ecf20Sopenharmony_ci mvi NO_FREE_SCB call set_seqint; 23718c2ecf20Sopenharmony_ci mvi SINDEX, SCB_LIST_NULL ret; 23728c2ecf20Sopenharmony_cidequeue_disc_scb: 23738c2ecf20Sopenharmony_ci mov SCBPTR, DISCONNECTED_SCBH; 23748c2ecf20Sopenharmony_ci mov DISCONNECTED_SCBH, SCB_NEXT; 23758c2ecf20Sopenharmony_ciEND_CRITICAL; 23768c2ecf20Sopenharmony_ci mvi DMAPARAMS, FIFORESET; 23778c2ecf20Sopenharmony_ci mov SCB_TAG jmp dma_scb; 23788c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 23798c2ecf20Sopenharmony_cidequeue_free_scb: 23808c2ecf20Sopenharmony_ci mov SCBPTR, FREE_SCBH; 23818c2ecf20Sopenharmony_ci mov FREE_SCBH, SCB_NEXT ret; 23828c2ecf20Sopenharmony_ciEND_CRITICAL; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ciadd_scb_to_disc_list: 23858c2ecf20Sopenharmony_ci/* 23868c2ecf20Sopenharmony_ci * Link this SCB into the DISCONNECTED list. This list holds the 23878c2ecf20Sopenharmony_ci * candidates for paging out an SCB if one is needed for a new command. 23888c2ecf20Sopenharmony_ci * Modifying the disconnected list is a critical(pause dissabled) section. 23898c2ecf20Sopenharmony_ci */ 23908c2ecf20Sopenharmony_ciBEGIN_CRITICAL; 23918c2ecf20Sopenharmony_ci mov SCB_NEXT, DISCONNECTED_SCBH; 23928c2ecf20Sopenharmony_ci mov DISCONNECTED_SCBH, SCBPTR ret; 23938c2ecf20Sopenharmony_ciEND_CRITICAL; 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ciset_seqint: 23968c2ecf20Sopenharmony_ci mov INTSTAT, SINDEX; 23978c2ecf20Sopenharmony_ci nop; 23988c2ecf20Sopenharmony_cireturn: 23998c2ecf20Sopenharmony_ci ret; 2400