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