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