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