1; $NetBSD: esiop.ss,v 1.22 2022/05/23 19:21:30 andvar Exp $ 2 3; 4; Copyright (c) 2002 Manuel Bouyer. 5; 6; Redistribution and use in source and binary forms, with or without 7; modification, are permitted provided that the following conditions 8; are met: 9; 1. Redistributions of source code must retain the above copyright 10; notice, this list of conditions and the following disclaimer. 11; 2. Redistributions in binary form must reproduce the above copyright 12; notice, this list of conditions and the following disclaimer in the 13; documentation and/or other materials provided with the distribution. 14; 15; THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 16; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18; ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 19; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25; SUCH DAMAGE. 26; 27 28ARCH 825 29 30; offsets in siop_common_xfer 31ABSOLUTE t_id = 40; 32ABSOLUTE t_msg_in = 48; 33ABSOLUTE t_ext_msg_in = 56; 34ABSOLUTE t_ext_msg_data = 64; 35ABSOLUTE t_msg_out = 72; 36ABSOLUTE t_cmd = 80; 37ABSOLUTE t_status = 88; 38ABSOLUTE t_data = 96; 39 40; offsets in the per-target lun table 41ABSOLUTE target_id = 0x0; 42ABSOLUTE target_luntbl = 0x8; 43ABSOLUTE target_luntbl_tag = 0xc; 44 45;; interrupt codes 46; interrupts that needs a valid target/lun/tag 47ABSOLUTE int_done = 0xff00; 48ABSOLUTE int_msgin = 0xff01; 49ABSOLUTE int_extmsgin = 0xff02; 50ABSOLUTE int_extmsgdata = 0xff03; 51ABSOLUTE int_disc = 0xff04; 52; interrupts that don't have a valid I/T/Q 53ABSOLUTE int_resfail = 0xff80; 54ABSOLUTE int_err = 0xffff; 55 56; We use the various scratch[a-j] registers to keep internal status: 57 58; scratchA1: offset in data DSA (for save data pointer) 59; scratchB: save/restore DSA in data loop 60; scratchC: current target/lun/tag 61; scratchC0: flags 62ABSOLUTE f_c_target = 0x01 ; target valid 63ABSOLUTE f_c_lun = 0x02 ; lun valid 64ABSOLUTE f_c_tag = 0x04 ; tag valid 65ABSOLUTE f_c_data = 0x08 ; data I/O in progress 66ABSOLUTE f_c_data_mask = 0xf7 ; ~f_c_data 67ABSOLUTE f_c_sdp = 0x10 ; got save data pointer message 68; scratchC[1-3]: target/lun/tag 69 70; scratchD: current DSA in start cmd ring 71; scratchE0: index in start cmd ring 72ABSOLUTE ncmd_slots = 256 ; number of slots in CMD ring 73ABSOLUTE ncmd_slots_last = 0 ; == ncmd_slots in a 8bit counter 74; flags in a cmd slot 75ABSOLUTE f_cmd_free = 0x01 ; this slot is free 76ABSOLUTE f_cmd_ignore = 0x02 ; this slot is not free but don't start it 77; offsets in a cmd slot 78ABSOLUTE o_cmd_dsa = 0; also holds f_cmd_* 79; size of a cmd slot (for DSA increments) 80ABSOLUTE cmd_slot_size = 4; 81 82; SCRATCHE1: last status 83 84; SCRATCHE2: current command done slot 85ABSOLUTE ndone_slots = 256 ; number of slots in CMD ring 86ABSOLUTE ndone_slots_last = 0 ; == ndonemd_slots in a 8bit counter 87; SCRATCHF: pointer in command done ring 88 89ENTRY cmdr0; 90ENTRY cmdr1; 91ENTRY cmdr2; 92ENTRY cmdr3; 93ENTRY doner0; 94ENTRY doner1; 95ENTRY doner2; 96ENTRY doner3; 97ENTRY reselect; 98ENTRY led_on1; 99ENTRY led_on2; 100ENTRY led_off; 101ENTRY status; 102ENTRY msgin; 103ENTRY msgin_ack; 104ENTRY get_extmsgdata; 105ENTRY send_msgout; 106ENTRY script_sched; 107ENTRY load_targtable; 108 109EXTERN tlq_offset; 110EXTERN saved_offset_offset; 111EXTERN abs_msgin2; 112 113EXTERN abs_sem; a 32bits word used a semaphore between script and driver 114ABSOLUTE sem_done = 0x01; there are pending done commands 115ABSOLUTE sem_start = 0x02; a CMD slot was freed 116 117PROC esiop_script: 118 119no_cmd: 120 LOAD SCRATCHB0, 4, abs_sem; pending done command ? 121 MOVE SCRATCHB0 & sem_done TO SFBR; 122 INTFLY 0, IF NOT 0x00; 123 MOVE SCRATCHB0 | sem_start TO SCRATCHB0; we are there because the 124 STORE NOFLUSH SCRATCHB0, 4, abs_sem; cmd ring is empty 125reselect: 126 MOVE 0x00 TO SCRATCHA1; 127 MOVE 0x00 TO SCRATCHC0; 128 MOVE 0xff TO SCRATCHE1; 129; a NOP by default; patched with MOVE GPREG | 0x01 to GPREG on compile-time 130; option "SIOP_SYMLED" 131led_off: 132 NOP; 133 WAIT RESELECT REL(reselect_fail); 134; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time 135; option "SIOP_SYMLED" 136led_on2: 137 NOP; 138 MOVE SSID & 0x0f to SFBR; 139 MOVE SFBR to SCRATCHC1; 140 MOVE SCRATCHC0 | f_c_target to SCRATCHC0; save target 141 CLEAR CARRY; 142 MOVE SCRATCHC1 SHL SFBR; 143 MOVE SFBR SHL DSA0; target * 4 in dsa 144 MOVE 0x0 to DSA1; 145 MOVE 0x0 to DSA2; 146 MOVE 0x0 to DSA3; 147; load DSA for the target table 148load_targtable: 149 MOVE DSA0 + 0x00 to DSA0; host will patch 0x0 with base of table 150 MOVE DSA1 + 0x00 to DSA1 with carry; 151 MOVE DSA2 + 0x00 to DSA2 with carry; 152 MOVE DSA3 + 0x00 to DSA3 with carry; now dsa -> basetable + target * 4 153 LOAD DSA0, 4, FROM 0; now load DSA for this target 154 SELECT FROM target_id, REL(nextisn); 155nextisn: 156 MOVE 1, abs_msgin2, WHEN MSG_IN; 157 MOVE SFBR & 0x07 to SCRATCHC2; 158 MOVE SCRATCHC0 | f_c_lun to SCRATCHC0; save LUN 159 CLEAR ACK and CARRY; 160 MOVE SCRATCHC2 SHL SFBR; 161 MOVE SFBR SHL SFBR; 162 MOVE SFBR SHL SFBR; lun * 8 163 MOVE DSA0 + SFBR TO DSA0; 164 MOVE DSA1 + 0x0 TO DSA1 with carry; 165 MOVE DSA2 + 0x0 TO DSA2 with carry; 166 MOVE DSA3 + 0x0 TO DSA3 with carry; 167 LOAD SCRATCHB0, 4, from target_luntbl_tag; in case it's a tagged cmd 168 LOAD DSA0, 4, from target_luntbl; load DSA for this LUN 169 JUMP REL(waitphase), WHEN NOT MSG_IN; 170 MOVE 1, abs_msgin2, WHEN MSG_IN; 171 CLEAR ACK; 172 JUMP REL(handle_msgin), IF NOT 0x20; not a simple tag message 173 MOVE 1, abs_msgin2, WHEN MSG_IN; get tag 174 MOVE SFBR to SCRATCHA2; 175 MOVE SFBR to SCRATCHC3; 176 MOVE SCRATCHC0 | f_c_tag to SCRATCHC0; save TAG 177 CALL REL(restoredsa); switch to tag table DSA 178 MOVE 0x0 to SCRATCHA3; 179 CLEAR CARRY; 180 MOVE SCRATCHA2 SHL SCRATCHA2; 181 MOVE SCRATCHA3 SHL SCRATCHA3; 182 MOVE SCRATCHA2 SHL SCRATCHA2; 183 MOVE SCRATCHA3 SHL SCRATCHA3; TAG * 4 to SCRATCHA(2,3) 184 MOVE SCRATCHA2 TO SFBR; 185 MOVE DSA0 + SFBR TO DSA0; 186 MOVE DSA1 + 0x00 TO DSA1 with CARRY; 187 MOVE DSA2 + 0x00 TO DSA2 with CARRY; 188 MOVE DSA3 + 0x00 TO DSA3 with CARRY; 189 MOVE SCRATCHA3 TO SFBR; 190 MOVE DSA1 + SFBR TO DSA1; 191 MOVE DSA2 + 0x00 TO DSA2 with CARRY; 192 MOVE DSA3 + 0x00 TO DSA3 with CARRY; SCRACHA(2,3) + DSA to DSA 193 LOAD DSA0, 4, from 0; load DSA for this tag 194msgin_ack: 195 CLEAR ACK; 196waitphase: 197 JUMP REL(msgout), WHEN MSG_OUT; 198 JUMP REL(msgin), WHEN MSG_IN; 199 JUMP REL(dataout), WHEN DATA_OUT; 200 JUMP REL(datain), WHEN DATA_IN; 201 JUMP REL(cmdout), WHEN CMD; 202 JUMP REL(status), WHEN STATUS; 203 INT int_err; 204 205handle_cmpl: 206 CALL REL(disconnect); 207; update offset if we did some data transfer 208 MOVE SCRATCHA1 TO SFBR; 209 JUMP REL(handle_cmpl_noxfer), if 0x00; 210 STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset; 211handle_cmpl_noxfer: 212 MOVE SCRATCHE1 to SFBR; 213 INT int_done, IF NOT 0x00; if status is not "done", let host handle it 214 MOVE SCRATCHF0 to SFBR; load pointer in done ring 215 MOVE SFBR to DSA0; 216 MOVE SCRATCHF1 to SFBR; 217 MOVE SFBR to DSA1; 218 MOVE SCRATCHF2 to SFBR; 219 MOVE SFBR to DSA2; 220 MOVE SCRATCHF3 to SFBR; 221 MOVE SFBR to DSA3; 222wait_free: 223 LOAD SCRATCHA0, 1, from 0; 224 MOVE SCRATCHA0 to SFBR; 225 JUMP REL(wait_free), if not 0; wait for slot to be free 226 STORE NOFLUSH SCRATCHC0, 4, from 0; save current target/lun/flag 227 MOVE SCRATCHF0 + 4 to SCRATCHF0; advance to next slot 228 MOVE SCRATCHF1 + 0 to SCRATCHF1 with carry; 229 MOVE SCRATCHF2 + 0 to SCRATCHF2 with carry; 230 MOVE SCRATCHF3 + 0 to SCRATCHF3 with carry; 231 MOVE SCRATCHE2 + 1 to SCRATCHE2; 232 MOVE SCRATCHE2 to SFBR; 233 JUMP REL(is_done), if not ndone_slots_last; 234doner0: 235 MOVE 0xff to SCRATCHF0; driver will change 0xff to base of ring 236doner1: 237 MOVE 0xff to SCRATCHF1; 238doner2: 239 MOVE 0xff to SCRATCHF2; 240doner3: 241 MOVE 0xff to SCRATCHF3; 242 MOVE 0 to SCRATCHE2; 243is_done: 244 LOAD SCRATCHB0, 4, abs_sem; signal that a command is done 245 MOVE SCRATCHB0 | sem_done TO SCRATCHB0; 246 STORE NOFLUSH SCRATCHB0, 4, abs_sem; 247; and attempt next command 248 249reselect_fail: 250 ; clear SIGP in ISTAT 251 MOVE CTEST2 & 0x40 TO SFBR; 252script_sched: 253; Load ring DSA 254 MOVE SCRATCHD0 to SFBR; 255 MOVE SFBR to DSA0; 256 MOVE SCRATCHD1 to SFBR; 257 MOVE SFBR to DSA1; 258 MOVE SCRATCHD2 to SFBR; 259 MOVE SFBR to DSA2; 260 MOVE SCRATCHD3 to SFBR; 261 MOVE SFBR to DSA3; 262 LOAD DSA0,4, from o_cmd_dsa; get DSA and flags for this slot 263 MOVE DSA0 & f_cmd_free to SFBR; check flags 264 JUMP REL(no_cmd), IF NOT 0x0; 265 MOVE DSA0 & f_cmd_ignore to SFBR; 266 JUMP REL(ignore_cmd), IF NOT 0x0; 267 LOAD SCRATCHC0, 4, FROM tlq_offset; 268; this slot is busy, attempt to exec command 269 SELECT ATN FROM t_id, REL(reselect); 270; select either succeeded or timed out. 271; if timed out the STO interrupt will be posted at the first SCSI bus access 272; waiting for a valid phase, so we have to do it now. If not a MSG_OUT phase, 273; this is an error anyway (we selected with ATN) 274 INT int_err, WHEN NOT MSG_OUT; 275ignore_cmd: 276 MOVE SCRATCHD0 to SFBR; restore scheduler DSA 277 MOVE SFBR to DSA0; 278 MOVE SCRATCHD1 to SFBR; 279 MOVE SFBR to DSA1; 280 MOVE SCRATCHD2 to SFBR; 281 MOVE SFBR to DSA2; 282 MOVE SCRATCHD3 to SFBR; 283 MOVE SFBR to DSA3; 284 MOVE SCRATCHE0 + 1 to SCRATCHE0; 285 MOVE SCRATCHD0 + cmd_slot_size to SCRATCHD0; 286 MOVE SCRATCHD1 + 0 to SCRATCHD1 WITH CARRY; 287 MOVE SCRATCHD2 + 0 to SCRATCHD2 WITH CARRY; 288 MOVE SCRATCHD3 + 0 to SCRATCHD3 WITH CARRY; 289 MOVE SCRATCHE0 TO SFBR; 290 JUMP REL(handle_cmd), IF NOT ncmd_slots_last; 291; reset pointers to beginning of area 292cmdr0: 293 MOVE 0xff to SCRATCHD0; correct value will be patched by driver 294cmdr1: 295 MOVE 0xff to SCRATCHD1; 296cmdr2: 297 MOVE 0xff to SCRATCHD2; 298cmdr3: 299 MOVE 0xff to SCRATCHD3; 300 MOVE 0x00 to SCRATCHE0; 301handle_cmd: 302; to avoid race condition we have to load the DSA value before setting the 303; free flag, so we have to use a temp register. 304; use SCRATCHB0 so that we can CALL restoredsa later 305 LOAD SCRATCHB0, 4, FROM o_cmd_dsa; load DSA for this command in temp reg 306 MOVE SCRATCHB0 | f_cmd_free to SCRATCHB0; mark slot as free 307 STORE noflush SCRATCHB0, 4, FROM o_cmd_dsa; 308 MOVE SCRATCHB0 & f_cmd_ignore to SFBR; 309 JUMP REL(script_sched), IF NOT 0x00; next command if ignore 310 MOVE SCRATCHB0 & 0xfc to SCRATCHB0; clear f_cmd_* 311 CALL REL(restoredsa); and move SCRATCHB to DSA 312 LOAD SCRATCHB0, 4, abs_sem; 313 MOVE SCRATCHB0 | sem_start TO SCRATCHB0; 314 STORE NOFLUSH SCRATCHB0, 4, abs_sem; 315 316; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time 317; option "SIOP_SYMLED" 318led_on1: 319 NOP; 320 MOVE 0x00 TO SCRATCHA1; 321 MOVE 0xff TO SCRATCHE1; 322;we can now send our identify message 323send_msgout: ; entry point for msgout after a msgin or status phase 324 SET ATN; 325 CLEAR ACK; 326msgout: 327 MOVE FROM t_msg_out, WHEN MSG_OUT; 328 CLEAR ATN; 329 JUMP REL(waitphase); 330 331 332handle_sdp: 333 CLEAR ACK; 334 MOVE SCRATCHC0 | f_c_sdp TO SCRATCHC0; 335 ; should get a disconnect message now 336msgin: 337 CLEAR ATN 338 MOVE FROM t_msg_in, WHEN MSG_IN; 339handle_msgin: 340 JUMP REL(handle_cmpl), IF 0x00 ; command complete message 341 JUMP REL(handle_sdp), IF 0x02 ; save data pointer message 342 JUMP REL(handle_extin), IF 0x01 ; extended message 343 INT int_msgin, IF NOT 0x04; 344 CALL REL(disconnect) ; disconnect message 345; if we didn't get sdp, no need to interrupt 346 MOVE SCRATCHC0 & f_c_sdp TO SFBR; 347 INT int_disc, IF not 0x00; 348; update offset if we did some data transfer 349 MOVE SCRATCHA1 TO SFBR; 350 JUMP REL(script_sched), if 0x00; 351 STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset; 352 JUMP REL(script_sched); 353 354cmdout: 355 MOVE FROM t_cmd, WHEN CMD; 356 JUMP REL(waitphase); 357status: 358 MOVE FROM t_status, WHEN STATUS; 359 MOVE SFBR TO SCRATCHE1; 360 JUMP REL(waitphase); 361datain: 362 CALL REL(savedsa); 363 MOVE SCRATCHC0 | f_c_data TO SCRATCHC0; 364 datain_loop: 365 MOVE FROM t_data, WHEN DATA_IN; 366 MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset 367 MOVE DSA0 + 8 to DSA0; 368 MOVE DSA1 + 0 to DSA1 WITH CARRY; 369 MOVE DSA2 + 0 to DSA2 WITH CARRY; 370 MOVE DSA3 + 0 to DSA3 WITH CARRY; 371 JUMP REL(datain_loop), WHEN DATA_IN; 372 CALL REL(restoredsa); 373 MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0; 374 JUMP REL(waitphase); 375 376dataout: 377 CALL REL(savedsa); 378 MOVE SCRATCHC0 | f_c_data TO SCRATCHC0; 379dataout_loop: 380 MOVE FROM t_data, WHEN DATA_OUT; 381 MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset 382 MOVE DSA0 + 8 to DSA0; 383 MOVE DSA1 + 0 to DSA1 WITH CARRY; 384 MOVE DSA2 + 0 to DSA2 WITH CARRY; 385 MOVE DSA3 + 0 to DSA3 WITH CARRY; 386 JUMP REL(dataout_loop), WHEN DATA_OUT; 387 CALL REL(restoredsa); 388 MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0; 389 JUMP REL(waitphase); 390 391savedsa: 392 MOVE DSA0 to SFBR; 393 MOVE SFBR to SCRATCHB0; 394 MOVE DSA1 to SFBR; 395 MOVE SFBR to SCRATCHB1; 396 MOVE DSA2 to SFBR; 397 MOVE SFBR to SCRATCHB2; 398 MOVE DSA3 to SFBR; 399 MOVE SFBR to SCRATCHB3; 400 RETURN; 401 402restoredsa: 403 MOVE SCRATCHB0 TO SFBR; 404 MOVE SFBR TO DSA0; 405 MOVE SCRATCHB1 TO SFBR; 406 MOVE SFBR TO DSA1; 407 MOVE SCRATCHB2 TO SFBR; 408 MOVE SFBR TO DSA2; 409 MOVE SCRATCHB3 TO SFBR; 410 MOVE SFBR TO DSA3; 411 RETURN; 412 413disconnect: 414 MOVE SCNTL2 & 0x7f TO SCNTL2; 415 CLEAR ATN; 416 CLEAR ACK; 417 WAIT DISCONNECT; 418 RETURN; 419 420handle_extin: 421 CLEAR ACK; 422 MOVE FROM t_ext_msg_in, WHEN MSG_IN; 423 INT int_extmsgin; /* let host fill in t_ext_msg_data */ 424get_extmsgdata: 425 CLEAR ACK; 426 MOVE FROM t_ext_msg_data, WHEN MSG_IN; 427 INT int_extmsgdata; 428 429PROC esiop_led_on: 430 MOVE GPREG & 0xfe TO GPREG; 431 432PROC esiop_led_off: 433 MOVE GPREG | 0x01 TO GPREG; 434