; $NetBSD: siop.ss,v 1.20 2005/11/18 23:10:32 bouyer Exp $ ; ; Copyright (c) 2000 Manuel Bouyer. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; 1. Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; 2. Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; 3. All advertising materials mentioning features or use of this software ; must display the following acknowledgement: ; This product includes software developed by Manuel Bouyer. ; 4. The name of the author may not be used to endorse or promote products ; derived from this software without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ARCH 720 ; offsets in siop_common_xfer ABSOLUTE t_id = 40; ABSOLUTE t_msg_in = 48; ABSOLUTE t_ext_msg_in = 56; ABSOLUTE t_ext_msg_data = 64; ABSOLUTE t_msg_out = 72; ABSOLUTE t_cmd = 80; ABSOLUTE t_status = 88; ABSOLUTE t_data = 96; ;; interrupt codes ; interrupts that need a valid DSA ABSOLUTE int_done = 0xff00; ABSOLUTE int_msgin = 0xff01; ABSOLUTE int_extmsgin = 0xff02; ABSOLUTE int_extmsgdata = 0xff03; ABSOLUTE int_disc = 0xff04; ABSOLUTE int_saveoffset = 0xff05; ; interrupts that don't have a valid DSA ABSOLUTE int_reseltarg = 0xff80; ABSOLUTE int_resellun = 0xff81; ABSOLUTE int_reseltag = 0xff82; ABSOLUTE int_resfail = 0xff83; ABSOLUTE int_err = 0xffff; ; flags for scratcha0 ABSOLUTE flag_sdp = 0x01 ; got save data pointer ABSOLUTE flag_data = 0x02 ; we're in data phase ABSOLUTE flag_data_mask = 0xfd ; ~flag_data ; main script symbols ENTRY waitphase; ENTRY send_msgout; ENTRY msgout; ENTRY msgin; ENTRY handle_msgin; ENTRY msgin_ack; ENTRY dataout; ENTRY datain; ENTRY cmdout; ENTRY status; ENTRY disconnect; ENTRY reselect; ENTRY reselected; ENTRY selected; ENTRY script_sched; ENTRY script_sched_slot0; ENTRY get_extmsgdata; ENTRY resel_targ0; ENTRY msgin_space; ENTRY lunsw_return; ENTRY led_on1; ENTRY led_on2; ENTRY led_off; EXTERN abs_script_sched_slot0; EXTERN abs_targ0; EXTERN abs_msgin; ; lun switch symbols ENTRY lun_switch_entry; ENTRY resel_lun0; ENTRY restore_scntl3; EXTERN abs_lunsw_return; ; tag switch symbols ENTRY tag_switch_entry; ENTRY resel_tag0; EXTERN abs_tag0; ; command reselect script symbols ENTRY rdsa0; ENTRY rdsa1; ENTRY rdsa2; ENTRY rdsa3; ENTRY ldsa_reload_dsa; ENTRY ldsa_select; ENTRY ldsa_data; EXTERN ldsa_abs_reselected; EXTERN ldsa_abs_reselect; EXTERN ldsa_abs_selected; EXTERN ldsa_abs_data; EXTERN ldsa_abs_slot; ; main script PROC siop_script: reselected: ; starting a new session, init 'local variables' MOVE 0 to SCRATCHA0 ; flags MOVE 0 to SCRATCHA1 ; DSA offset (for S/G save data pointer) MOVE SCRATCHA3 to SFBR ; pending message ? JUMP REL(handle_msgin), IF not 0x20; waitphase: JUMP REL(msgout), WHEN MSG_OUT; JUMP REL(msgin), WHEN MSG_IN; JUMP REL(dataout), WHEN DATA_OUT; JUMP REL(datain), WHEN DATA_IN; JUMP REL(cmdout), WHEN CMD; JUMP REL(status), WHEN STATUS; INT int_err; reselect_fail: ; check that host asserted SIGP, this'll clear SIGP in ISTAT MOVE CTEST2 & 0x40 TO SFBR; INT int_resfail, IF 0x00; ; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time ; option "SIOP_SYMLED" led_on1: NOP; script_sched: ; Clear DSA and init status MOVE 0xff to DSA0; MOVE 0xff to DSA1; MOVE 0xff to DSA2; MOVE 0xff to DSA3; MOVE 0 to SCRATCHA0 ; flags MOVE 0 to SCRATCHA1 ; DSA offset (for S/G save data pointer) ; the script scheduler: siop_start() we set the absolute jump addr, and then ; changes the FALSE to TRUE. The select script will change it back to false ; once the target is selected. ; The RAM could hold 370 slot entry, we limit it to 40. Should be more than ; enough. script_sched_slot0: JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; JUMP abs_script_sched_slot0, IF FALSE; ; Nothing to do, wait for reselect reselect: ; Clear DSA and init status MOVE 0xff to DSA0; MOVE 0xff to DSA1; MOVE 0xff to DSA2; MOVE 0xff to DSA3; MOVE 0x00 to SCRATCHA2; no tag MOVE 0x20 to SCRATCHA3; simple tag msg, ignored by reselected: ; a NOP by default; patched with MOVE GPREG | 0x01 to GPREG on compile-time ; option "SIOP_SYMLED" led_off: NOP; WAIT RESELECT REL(reselect_fail) ; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time ; option "SIOP_SYMLED" led_on2: NOP; MOVE SSID & 0x8f to SFBR MOVE SFBR to SCRATCHA0 ; save reselect ID ; find the right param for this target resel_targ0: JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; JUMP abs_targ0, IF 0xff; INT int_reseltarg; lunsw_return: MOVE 1, abs_msgin, WHEN MSG_IN; MOVE SFBR & 0x07 to SCRATCHA1; save LUN CLEAR ACK; RETURN, WHEN NOT MSG_IN; If no more message, jump to lun sw MOVE 1, abs_msgin, WHEN MSG_IN; CLEAR ACK; MOVE SFBR to SCRATCHA3; save message RETURN, IF NOT 0x20; jump to lun sw if not simple tag msg MOVE 1, abs_msgin, WHEN MSG_IN; get tag CLEAR ACK; MOVE SFBR to SCRATCHA2; save tag RETURN; jump to lun sw handle_sdp: CLEAR ACK; MOVE SCRATCHA0 | flag_sdp TO SCRATCHA0; ; should get a disconnect message now msgin: CLEAR ATN MOVE FROM t_msg_in, WHEN MSG_IN; handle_msgin: JUMP REL(handle_cmpl), IF 0x00 ; command complete message JUMP REL(handle_sdp), IF 0x02 ; save data pointer message JUMP REL(handle_extin), IF 0x01 ; extended message INT int_msgin, IF not 0x04; CALL REL(disconnect) ; disconnect message; ; if we didn't get sdp, no need to interrupt MOVE SCRATCHA0 & flag_sdp TO SFBR; INT int_disc, IF not 0x00; ; update offset if we did some data transfer MOVE SCRATCHA1 TO SFBR; JUMP REL(script_sched), if 0x00; INT int_saveoffset; msgin_ack: selected: CLEAR ACK; JUMP REL(waitphase); ; entry point for msgout after a msgin or status phase send_msgout: SET ATN; CLEAR ACK; msgout: MOVE FROM t_msg_out, WHEN MSG_OUT; CLEAR ATN; JUMP REL(waitphase); cmdout: MOVE FROM t_cmd, WHEN CMD; JUMP REL(waitphase); status: MOVE FROM t_status, WHEN STATUS; JUMP REL(waitphase); datain: CALL REL(savedsa); MOVE SCRATCHA0 | flag_data TO SCRATCHA0; datain_loop: MOVE FROM t_data, WHEN DATA_IN; MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset MOVE DSA0 + 8 to DSA0; MOVE DSA1 + 0 to DSA1 WITH CARRY; MOVE DSA2 + 0 to DSA2 WITH CARRY; MOVE DSA3 + 0 to DSA3 WITH CARRY; JUMP REL(datain_loop), WHEN DATA_IN; CALL REL(restoredsa); MOVE SCRATCHA0 & flag_data_mask TO SCRATCHA0; JUMP REL(waitphase); dataout: CALL REL(savedsa); MOVE SCRATCHA0 | flag_data TO SCRATCHA0; dataout_loop: MOVE FROM t_data, WHEN DATA_OUT; MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset MOVE DSA0 + 8 to DSA0; MOVE DSA1 + 0 to DSA1 WITH CARRY; MOVE DSA2 + 0 to DSA2 WITH CARRY; MOVE DSA3 + 0 to DSA3 WITH CARRY; JUMP REL(dataout_loop), WHEN DATA_OUT; CALL REL(restoredsa); MOVE SCRATCHA0 & flag_data_mask TO SCRATCHA0; JUMP REL(waitphase); savedsa: MOVE DSA0 to SFBR; MOVE SFBR to SCRATCHB0; MOVE DSA1 to SFBR; MOVE SFBR to SCRATCHB1; MOVE DSA2 to SFBR; MOVE SFBR to SCRATCHB2; MOVE DSA3 to SFBR; MOVE SFBR to SCRATCHB3; RETURN; restoredsa: MOVE SCRATCHB0 TO SFBR; MOVE SFBR TO DSA0; MOVE SCRATCHB1 TO SFBR; MOVE SFBR TO DSA1; MOVE SCRATCHB2 TO SFBR; MOVE SFBR TO DSA2; MOVE SCRATCHB3 TO SFBR; MOVE SFBR TO DSA3; RETURN; disconnect: MOVE SCNTL2 & 0x7f TO SCNTL2; CLEAR ATN; CLEAR ACK; WAIT DISCONNECT; RETURN; handle_cmpl: CALL REL(disconnect); INT int_done; handle_extin: CLEAR ACK; MOVE FROM t_ext_msg_in, WHEN MSG_IN; INT int_extmsgin; /* let host fill in t_ext_msg_data */ get_extmsgdata: CLEAR ACK; MOVE FROM t_ext_msg_data, WHEN MSG_IN; INT int_extmsgdata; msgin_space: NOP; space to store msgin when reselect ;; per-target switch script for LUNs ; hack: we first do a call to the target-specific code, so that a return ; in the main switch will jump to the lun switch. PROC lun_switch: restore_scntl3: MOVE 0xff TO SCNTL3; MOVE 0xff TO SXFER; JUMP abs_lunsw_return; lun_switch_entry: CALL REL(restore_scntl3); MOVE SCRATCHA1 TO SFBR; resel_lun0: INT int_resellun; ;; Per-device switch script for tag PROC tag_switch: tag_switch_entry: MOVE SCRATCHA2 TO SFBR; restore tag resel_tag0: JUMP abs_tag0, IF 0x00; JUMP abs_tag0, IF 0x01; JUMP abs_tag0, IF 0x02; JUMP abs_tag0, IF 0x03; JUMP abs_tag0, IF 0x04; JUMP abs_tag0, IF 0x05; JUMP abs_tag0, IF 0x06; JUMP abs_tag0, IF 0x07; JUMP abs_tag0, IF 0x08; JUMP abs_tag0, IF 0x09; JUMP abs_tag0, IF 0x0a; JUMP abs_tag0, IF 0x0b; JUMP abs_tag0, IF 0x0c; JUMP abs_tag0, IF 0x0d; JUMP abs_tag0, IF 0x0e; JUMP abs_tag0, IF 0x0f; INT int_reseltag; ;; per-command script: select, and called after a reselect to load DSA PROC load_dsa: ; Can't use MOVE MEMORY to load DSA, doesn't work I/O mapped rdsa0: MOVE 0xf0 to DSA0; rdsa1: MOVE 0xf1 to DSA1; rdsa2: MOVE 0xf2 to DSA2; rdsa3: MOVE 0xf3 to DSA3; RETURN; ldsa_reload_dsa: CALL REL(rdsa0); JUMP ldsa_abs_reselected; ldsa_select: CALL REL(rdsa0); SELECT ATN FROM t_id, ldsa_abs_reselect; MOVE MEMORY 4, ldsa_abs_data, ldsa_abs_slot; JUMP ldsa_abs_selected; ldsa_data: NOP; contains data used by the MOVE MEMORY PROC siop_led_on: MOVE GPREG & 0xfe TO GPREG; PROC siop_led_off: MOVE GPREG | 0x01 TO GPREG;