📄 aic79xx.seq
字号:
call phase_lock; cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; mov SCBPTR jmp p_mesgout_onebyte;/* * Interrupt the driver, and allow it to handle this message * phase and any required retries. */p_mesgout_from_host: cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; jmp host_message_loop;p_mesgout_onebyte: mvi CLRSINT1, CLRATNO; mov SCSIDAT, SINDEX;/* * If the next bus phase after ATN drops is message out, it means * that the target is requesting that the last message(s) be resent. */ call phase_lock; cmp LASTPHASE, P_MESGOUT je p_mesgout_retry;p_mesgout_done: mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ mov LAST_MSG, MSG_OUT; mvi MSG_OUT, MSG_NOOP; /* No message left */ jmp ITloop;/* * Message in phase. Bytes are read using Automatic PIO mode. */p_mesgin: /* read the 1st message byte */ mvi ACCUM call inb_first; test A,MSG_IDENTIFYFLAG jnz mesgin_identify; cmp A,MSG_DISCONNECT je mesgin_disconnect; cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; cmp ALLZEROS,A je mesgin_complete; cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; cmp A,MSG_NOOP je mesgin_done;/* * Pushed message loop to allow the kernel to * run it's own message state engine. To avoid an * extra nop instruction after signaling the kernel, * we perform the phase_lock before checking to see * if we should exit the loop and skip the phase_lock * in the ITloop. Performing back to back phase_locks * shouldn't hurt, but why do it twice... */host_message_loop: call phase_lock; /* Benign the first time through. */ SET_SEQINTCODE(HOST_MSG_LOOP) cmp RETURN_1, EXIT_MSG_LOOP je ITloop; cmp RETURN_1, CONT_MSG_LOOP_WRITE jne . + 3; mov SCSIDAT, RETURN_2; jmp host_message_loop; /* Must be CONT_MSG_LOOP_READ */ mov NONE, SCSIDAT; /* ACK Byte */ jmp host_message_loop;mesgin_ign_wide_residue: mov SAVED_MODE, MODE_PTR; SET_MODE(M_SCSI, M_SCSI) shr NEGOADDR, 4, SAVED_SCSIID; mov A, NEGCONOPTS; RESTORE_MODE(SAVED_MODE) test A, WIDEXFER jz mesgin_reject; /* Pull the residue byte */ mvi REG0 call inb_next; cmp REG0, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done; SET_SEQINTCODE(IGN_WIDE_RES) jmp mesgin_done;mesgin_proto_violation: SET_SEQINTCODE(PROTO_VIOLATION) jmp mesgin_done;mesgin_reject: mvi MSG_MESSAGE_REJECT call mk_mesg;mesgin_done: mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ jmp ITloop;#define INDEX_DISC_LIST(scsiid, lun) \ and A, 0xC0, scsiid; \ or SCBPTR, A, lun; \ clr SCBPTR[1]; \ and SINDEX, 0x30, scsiid; \ shr SINDEX, 3; /* Multiply by 2 */ \ add SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF); \ mvi SINDEX[1], ((SCB_DISCONNECTED_LISTS >> 8) & 0xFF)mesgin_identify: /* * Determine whether a target is using tagged or non-tagged * transactions by first looking at the transaction stored in * the per-device, disconnected array. If there is no untagged * transaction for this target, this must be a tagged transaction. */ and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); bmov DINDEX, SINDEX, 2; bmov REG0, SINDIR, 2; cmp REG0[1], SCB_LIST_NULL je snoop_tag; /* Untagged. Clear the busy table entry and setup the SCB. */ bmov DINDIR, ALLONES, 2; bmov SCBPTR, REG0, 2; jmp setup_SCB;/* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. * If we get one, we use the tag returned to find the proper * SCB. After receiving the tag, look for the SCB at SCB locations tag and * tag + 256. */snoop_tag: if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x80; } mov NONE, SCSIDAT; /* ACK Identify MSG */ call phase_lock; if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x1; } cmp LASTPHASE, P_MESGIN jne not_found_ITloop; if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x2; } cmp SCSIBUS, MSG_SIMPLE_Q_TAG jne not_found;get_tag: clr SCBPTR[1]; mvi SCBPTR call inb_next; /* tag value */verify_scb: test SCB_CONTROL,DISCONNECTED jz verify_other_scb; mov A, SAVED_SCSIID; cmp SCB_SCSIID, A jne verify_other_scb; mov A, SAVED_LUN; cmp SCB_LUN, A je setup_SCB_disconnected;verify_other_scb: xor SCBPTR[1], 1; test SCBPTR[1], 0xFF jnz verify_scb; jmp not_found;/* * Ensure that the SCB the tag points to is for * an SCB transaction to the reconnecting target. */setup_SCB: if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x10; } test SCB_CONTROL,DISCONNECTED jz not_found;setup_SCB_disconnected: and SCB_CONTROL,~DISCONNECTED; clr SEQ_FLAGS; /* make note of IDENTIFY */ test SCB_SGPTR, SG_LIST_NULL jnz . + 3; bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; call allocate_fifo; /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; mvi HOST_MSG call mk_mesg; jmp mesgin_done;not_found: SET_SEQINTCODE(NO_MATCH) jmp mesgin_done;not_found_ITloop: SET_SEQINTCODE(NO_MATCH) jmp ITloop;/* * We received a "command complete" message. Put the SCB on the complete * queue and trigger a completion interrupt via the idle loop. Before doing * so, check to see if there * is a residual or the status byte is something other than STATUS_GOOD (0). * In either of these conditions, we upload the SCB back to the host so it can * process this information. In the case of a non zero status byte, we * additionally interrupt the kernel driver synchronously, allowing it to * decide if sense should be retrieved. If the kernel driver wishes to request * sense, it will fill the kernel SCB with a request sense command, requeue * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting * RETURN_1 to SEND_SENSE. */mesgin_complete: /* * If ATN is raised, we still want to give the target a message. * Perhaps there was a parity error on this last message byte. * Either way, the target should take us to message out phase * and then attempt to complete the command again. We should use a * critical section here to guard against a timeout triggering * for this command and setting ATN while we are still processing * the completion. test SCSISIGI, ATNI jnz mesgin_done; */ /* * If we are identified and have successfully sent the CDB, * any status will do. Optimize this fast path. */ test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; /* * If the target never sent an identify message but instead went * to mesgin to give an invalid message, let the host abort us. */ test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; /* * If we recevied good status but never successfully sent the * cdb, abort the command. */ test SCB_SCSI_STATUS,0xff jnz complete_accepted; test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation;complete_accepted: /* * See if we attempted to deliver a message but the target ingnored us. */ test SCB_CONTROL, MK_MESSAGE jz complete_nomsg; SET_SEQINTCODE(MKMSG_FAILED)complete_nomsg: call queue_scb_completion; jmp await_busfree;freeze_queue: /* Cancel any pending select-out. */ test SSTAT0, SELDO|SELINGO jnz . + 2; and SCSISEQ0, ~ENSELO; mov ACCUM_SAVE, A; clr A; add QFREEZE_COUNT, 1; adc QFREEZE_COUNT[1], A; or SEQ_FLAGS2, SELECTOUT_QFROZEN; mov A, ACCUM_SAVE ret;/* * Complete the current FIFO's SCB if data for this same * SCB is not transferring in the other FIFO. */SET_SRC_MODE M_DFF1;SET_DST_MODE M_DFF1;pkt_complete_scb_if_fifos_idle: bmov ARG_1, SCBPTR, 2; mvi DFFSXFRCTL, CLRCHN; SET_MODE(M_SCSI, M_SCSI) bmov SCBPTR, ARG_1, 2; test SCB_FIFO_USE_COUNT, 0xFF jnz return;queue_scb_completion: test SCB_SCSI_STATUS,0xff jnz bad_status; /* * Check for residuals */ test SCB_SGPTR, SG_LIST_NULL jnz complete; /* No xfer */ test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;complete: bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret;bad_status: cmp SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb; call freeze_queue;upload_scb: /* * Restore SCB TAG since we reuse this field * in the sequencer. We don't want to corrupt * it on the host. */ bmov SCB_TAG, SCBPTR, 2; bmov SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2; bmov COMPLETE_DMA_SCB_HEAD, SCBPTR, 2; or SCB_SGPTR, SG_STATUS_VALID ret;/* * Is it a disconnect message? Set a flag in the SCB to remind us * and await the bus going free. If this is an untagged transaction * store the SCB id for it in our untagged target table for lookup on * a reselction. */mesgin_disconnect: /* * If ATN is raised, we still want to give the target a message. * Perhaps there was a parity error on this last message byte * or we want to abort this command. Either way, the target * should take us to message out phase and then attempt to * disconnect again. * XXX - Wait for more testing. test SCSISIGI, ATNI jnz mesgin_done; */ test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jnz mesgin_proto_violation; or SCB_CONTROL,DISCONNECTED; test SCB_CONTROL, TAG_ENB jnz await_busfree;queue_disc_scb: bmov REG0, SCBPTR, 2; INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); bmov DINDEX, SINDEX, 2; bmov DINDIR, REG0, 2; bmov SCBPTR, REG0, 2; /* FALLTHROUGH */await_busfree: and SIMODE1, ~ENBUSFREE; if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) { /* * In the BUSFREEREV_BUG case, the * busfree status was cleared at the * beginning of the connection. */ mvi CLRSINT1,CLRBUSFREE; } mov NONE, SCSIDAT; /* Ack the last byte */ test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz await_busfree_not_m_dff;SET_SRC_MODE M_DFF1;SET_DST_MODE M_DFF1;await_busfree_clrchn: mvi DFFSXFRCTL, CLRCHN;await_busfree_not_m_dff: call clear_target_state; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz idle_loop; SET_SEQINTCODE(MISSED_BUSFREE)/* * Save data pointers message: * Copying RAM values back to SCB, for Save Data Pointers message, but * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. * Ack the message as soon as possible. */SET_SRC_MODE M_DFF1;SET_DST_MODE M_DFF1;mesgin_sdptrs: mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ test SEQ_FLAGS, DPHASE jz ITloop; call save_pointers; jmp ITloop;save_pointers: /* * If we are asked to save our position at the end of the * transfer, just mark us at the end rather than perform a * full save. */ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz save_pointers_full; or SCB_SGPTR, SG_LIST_NULL ret;save_pointers_full: /* * The SCB_DATAPTR becomes the current SHADDR. * All other information comes directly from our residual * state. */ bmov SCB_DATAPTR, SHADDR, 8; bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8 ret;/* * Restore pointers message? Data pointers are recopied from the * SCB anytime we enter a data phase for the first time, so all * we need to do is clear the DPHASE flag and let the data phase * code do the rest. We also reset/reallocate the FIFO to make * sure we have a clean start for the next data or command phase. */mesgin_rdptrs: and SEQ_FLAGS, ~DPHASE; test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo; mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; SET_MODE(M_SCSI, M_SCSI)msgin_rdptrs_get_fifo: call allocate_fifo; jmp mesgin_done;clear_target_state: mvi LASTPHASE, P_BUSFREE; /* clear target specific flags */ mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;phase_lock: if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) { /* * Don't ignore persistent REQ assertions just because * they were asserted within the bus settle delay window. * This allows us to tolerate devices like the GEM318 * that violate the SCSI spec. We are careful not to * count REQ while we are waiting for it to fall during * an async phase due to our asserted ACK. Each * sequencer instruction takes ~25ns, so the REQ must * last at least 100ns in order to be counted as a true * REQ. */ test SCSIPHASE, 0xFF jnz phase_locked; test SCSISIGI, ACKI jnz phase_lock; test SCSISIGI, REQI jz phase_lock; test SCSIPHASE, 0xFF jnz phase_locked; test SCSISIGI, ACKI jnz phase_lock; test SCSISIGI, REQI jz phase_lock;phase_locked: } else { test SCSIPHASE, 0xFF jz .; } test SSTAT1, SCSIPERR jnz phase_lock;phase_lock_latch_phase: and LASTPHASE, PHASE_MASK, SCSISIGI ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -