esiop.ss revision 1.16
1;	$NetBSD: esiop.ss,v 1.16 2003/10/05 17:48:49 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 abs_msgin2;
116
117EXTERN abs_sem; a 32bits word used a semaphore between script and driver
118ABSOLUTE sem_done = 0x01; there are pending done commands
119ABSOLUTE sem_start = 0x02; a CMD slot was freed
120
121PROC  esiop_script:
122
123no_cmd:
124	LOAD SCRATCHB0, 4, abs_sem; pending done command ?
125	MOVE SCRATCHB0 & sem_done TO SFBR;
126	INTFLY 0, IF NOT 0x00; 
127	MOVE SCRATCHB0 | sem_start TO SCRATCHB0; we are there because the 
128	STORE NOFLUSH SCRATCHB0, 4, abs_sem;     cmd ring is empty
129reselect:
130	MOVE 0x00 TO SCRATCHA1;
131	MOVE 0x00 TO SCRATCHC0;
132	MOVE 0xff TO SCRATCHE1;
133; a NOP by default; patched with MOVE GPREG | 0x01 to GPREG on compile-time
134; option "SIOP_SYMLED"
135led_off:
136	NOP;
137	WAIT RESELECT REL(reselect_fail);
138; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time
139; option "SIOP_SYMLED"
140led_on2:
141        NOP;
142	MOVE SSID & 0x0f to SFBR;
143	MOVE SFBR to SCRATCHC1;
144	MOVE SCRATCHC0 | f_c_target to SCRATCHC0; save target
145	CLEAR CARRY;
146	MOVE SCRATCHC1 SHL SFBR;
147	MOVE SFBR SHL DSA0; target * 4 in dsa
148	MOVE 0x0 to DSA1;
149	MOVE 0x0 to DSA2;
150	MOVE 0x0 to DSA3;
151; load DSA for the target table
152load_targtable:
153	MOVE DSA0 + 0x00 to DSA0; host will patch 0x0 with base of table
154	MOVE DSA1 + 0x00 to DSA1 with carry;
155	MOVE DSA2 + 0x00 to DSA2 with carry;
156	MOVE DSA3 + 0x00 to DSA3 with carry; now dsa -> basetable + target * 4
157	LOAD DSA0, 4, FROM 0; now load DSA for this target
158	SELECT FROM target_id, REL(nextisn);
159nextisn:
160	MOVE 1, abs_msgin2, WHEN MSG_IN;
161	MOVE SFBR & 0x07 to SCRATCHC2;
162	MOVE SCRATCHC0 | f_c_lun to SCRATCHC0; save LUN
163	CLEAR ACK and CARRY;
164	MOVE SCRATCHC2 SHL SFBR; 
165	MOVE SFBR SHL SFBR;
166	MOVE SFBR SHL SFBR; lun * 8
167	MOVE DSA0 + SFBR TO DSA0;
168	MOVE DSA1 + 0x0 TO DSA1 with carry;
169	MOVE DSA2 + 0x0 TO DSA2 with carry;
170	MOVE DSA3 + 0x0 TO DSA3 with carry;
171	LOAD SCRATCHB0, 4, from target_luntbl_tag; in case it's a tagged cmd
172	LOAD DSA0, 4, from target_luntbl; load DSA for this LUN
173	JUMP REL(waitphase), WHEN NOT MSG_IN;
174	MOVE 1, abs_msgin2, WHEN MSG_IN;
175	CLEAR ACK;
176	JUMP REL(handle_msgin), IF NOT 0x20; not a simple tag message
177	MOVE 1, abs_msgin2, WHEN MSG_IN; get tag
178	MOVE SFBR to SCRATCHA2;
179	MOVE SFBR to SCRATCHC3;
180	MOVE SCRATCHC0 | f_c_tag to SCRATCHC0; save TAG
181	CALL REL(restoredsa); switch to tag table DSA
182	MOVE 0x0 to SCRATCHA3;
183	CLEAR CARRY;
184	MOVE SCRATCHA2 SHL SCRATCHA2;
185	MOVE SCRATCHA3 SHL SCRATCHA3;
186	MOVE SCRATCHA2 SHL SCRATCHA2;
187	MOVE SCRATCHA3 SHL SCRATCHA3; TAG * 4 to SCRATCHA(2,3)
188	MOVE SCRATCHA2 TO SFBR;
189	MOVE DSA0 + SFBR TO DSA0;
190	MOVE DSA1 + 0x00 TO DSA1 with CARRY;
191	MOVE DSA2 + 0x00 TO DSA2 with CARRY;
192	MOVE DSA3 + 0x00 TO DSA3 with CARRY;
193	MOVE SCRATCHA3 TO SFBR;
194	MOVE DSA1 + SFBR TO DSA1;
195	MOVE DSA2 + 0x00 TO DSA2 with CARRY;
196	MOVE DSA3 + 0x00 TO DSA3 with CARRY; SCRACHA(2,3) + DSA to DSA
197	LOAD DSA0, 4, from 0; load DSA for this tag
198msgin_ack:
199	CLEAR ACK;
200waitphase:
201	JUMP REL(msgout), WHEN MSG_OUT;
202	JUMP REL(msgin), WHEN MSG_IN;
203	JUMP REL(dataout), WHEN DATA_OUT;
204	JUMP REL(datain), WHEN DATA_IN;
205	JUMP REL(cmdout), WHEN CMD;
206	JUMP REL(status), WHEN STATUS;
207	INT int_err;
208
209handle_cmpl:
210	CALL REL(disconnect);
211	MOVE SCRATCHE1 to SFBR;
212	INT int_done, IF NOT 0x00; if status is not "done", let host handle it
213	MOVE SCRATCHF0 to SFBR; load pointer in done ring
214	MOVE SFBR to DSA0;
215	MOVE SCRATCHF1 to SFBR;
216	MOVE SFBR to DSA1;
217	MOVE SCRATCHF2 to SFBR;
218	MOVE SFBR to DSA2;
219	MOVE SCRATCHF3 to SFBR;
220	MOVE SFBR to DSA3;
221wait_free:
222	LOAD SCRATCHA0, 1, from 0;
223	MOVE SCRATCHA0 to SFBR;
224	JUMP REL(wait_free), if not 0; wait for slot to be free
225	STORE NOFLUSH SCRATCHC0, 4, from 0; save current target/lun/flag
226	MOVE SCRATCHF0 + 4 to SCRATCHF0; advance to next slot
227	MOVE SCRATCHF1 + 0 to SCRATCHF1 with carry;
228	MOVE SCRATCHF2 + 0 to SCRATCHF2 with carry;
229	MOVE SCRATCHF3 + 0 to SCRATCHF3 with carry;
230	MOVE SCRATCHE2 + 1 to SCRATCHE2;
231	MOVE SCRATCHE2 to SFBR;
232	JUMP REL(is_done), if not ndone_slots_last;
233doner0:
234	MOVE 0xff to SCRATCHF0; driver will change 0xff to base of ring
235doner1:
236	MOVE 0xff to SCRATCHF1;
237doner2:
238	MOVE 0xff to SCRATCHF2;
239doner3:
240	MOVE 0xff to SCRATCHF3;
241	MOVE 0  to SCRATCHE2;
242is_done:
243	LOAD SCRATCHB0, 4, abs_sem; signal that a command is done
244	MOVE SCRATCHB0 | sem_done TO SCRATCHB0;
245	STORE NOFLUSH SCRATCHB0, 4, abs_sem;
246; and attempt next command
247
248reselect_fail:
249	; clear SIGP in ISTAT
250	MOVE CTEST2 & 0x40 TO SFBR;
251script_sched:
252; Load ring DSA
253	MOVE SCRATCHD0 to SFBR;
254	MOVE SFBR to DSA0;
255	MOVE SCRATCHD1 to SFBR;
256	MOVE SFBR to DSA1;
257	MOVE SCRATCHD2 to SFBR;
258	MOVE SFBR to DSA2;
259	MOVE SCRATCHD3 to SFBR;
260	MOVE SFBR to DSA3;
261	LOAD DSA0,4, from o_cmd_dsa; get DSA and flags for this slot
262	MOVE DSA0 & f_cmd_free to SFBR; check flags
263	JUMP REL(no_cmd), IF NOT 0x0;
264	MOVE DSA0 & f_cmd_ignore to SFBR;
265	JUMP REL(ignore_cmd), IF NOT 0x0;
266	LOAD SCRATCHC0, 4, FROM tlq_offset;
267; this slot is busy, attempt to exec command
268	SELECT ATN FROM t_id, REL(reselect);
269; select either succeeded or timed out.
270; if timed out the STO interrupt will be posted at the first SCSI bus access
271; waiting for a valid phase, so we have to do it now. If not a MSG_OUT phase,
272; this is an error anyway (we selected with ATN)
273	INT int_err, WHEN NOT MSG_OUT;
274ignore_cmd:
275	MOVE SCRATCHD0 to SFBR; restore scheduler DSA
276	MOVE SFBR to DSA0;
277	MOVE SCRATCHD1 to SFBR;
278	MOVE SFBR to DSA1;
279	MOVE SCRATCHD2 to SFBR;
280	MOVE SFBR to DSA2;
281	MOVE SCRATCHD3 to SFBR;
282	MOVE SFBR to DSA3;
283	MOVE SCRATCHE0 + 1 to SCRATCHE0;
284	MOVE SCRATCHD0 + cmd_slot_size to SCRATCHD0; 
285	MOVE SCRATCHD1 + 0 to SCRATCHD1 WITH CARRY;
286	MOVE SCRATCHD2 + 0 to SCRATCHD2 WITH CARRY;
287	MOVE SCRATCHD3 + 0 to SCRATCHD3 WITH CARRY;
288	MOVE SCRATCHE0 TO SFBR;
289	JUMP REL(handle_cmd), IF  NOT ncmd_slots_last;
290; reset pointers to beggining of area
291cmdr0:
292	MOVE 0xff to SCRATCHD0; correct value will be patched by driver
293cmdr1:
294	MOVE 0xff to SCRATCHD1;
295cmdr2:
296	MOVE 0xff to SCRATCHD2;
297cmdr3:
298	MOVE 0xff to SCRATCHD3;
299	MOVE 0x00 to SCRATCHE0;
300handle_cmd:
301; to avoid race condition we have to load the DSA value before setting the
302; free flag, so we have to use a temp register.
303; use SCRATCHB0 so that we can CALL restoredsa later
304	LOAD SCRATCHB0, 4, FROM o_cmd_dsa; load DSA for this command in temp reg
305	MOVE SCRATCHB0 | f_cmd_free to SCRATCHB0; mark slot as free
306	STORE noflush SCRATCHB0, 4, FROM o_cmd_dsa;
307	MOVE SCRATCHB0 & f_cmd_ignore to SFBR;
308	JUMP REL(script_sched), IF NOT 0x00; next command if ignore
309	MOVE SCRATCHB0 & 0xfc to SCRATCHB0; clear f_cmd_*
310	CALL REL(restoredsa); and move SCRATCHB to DSA
311	LOAD SCRATCHB0, 4, abs_sem;
312	MOVE SCRATCHB0 | sem_start TO SCRATCHB0;
313	STORE NOFLUSH SCRATCHB0, 4, abs_sem;
314
315; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time
316; option "SIOP_SYMLED"
317led_on1:
318	NOP;
319	MOVE 0x00 TO SCRATCHA1;
320	MOVE 0xff TO SCRATCHE1;
321;we can now send our identify message
322send_msgout: ; entry point for msgout after a msgin or status phase
323	SET ATN;
324	CLEAR ACK;
325msgout: 
326        MOVE FROM t_msg_out, WHEN MSG_OUT;
327	CLEAR ATN;  
328	JUMP REL(waitphase);
329
330
331handle_sdp:
332	CLEAR ACK;
333	MOVE SCRATCHC0 | f_c_sdp TO SCRATCHC0;
334	; should get a disconnect message now
335msgin:
336	CLEAR ATN
337	MOVE FROM t_msg_in, WHEN MSG_IN;
338handle_msgin:
339	JUMP REL(handle_cmpl), IF 0x00	; command complete message
340	JUMP REL(handle_sdp), IF 0x02	; save data pointer message
341	JUMP REL(handle_extin), IF 0x01	; extended message
342	INT int_msgin, IF NOT 0x04;
343	CALL REL(disconnect)		; disconnect message
344; if we didn't get sdp, or if offset is 0, no need to interrupt
345	MOVE SCRATCHC0 & f_c_sdp TO SFBR;
346	JUMP REL(script_sched), if 0x00;
347	MOVE SCRATCHA1 TO SFBR;
348	JUMP REL(script_sched), if 0x00;
349; Ok, we need to save data pointers
350	INT int_disc;
351
352cmdout:
353        MOVE FROM t_cmd, WHEN CMD; 
354	JUMP REL(waitphase);
355status: 
356        MOVE FROM t_status, WHEN STATUS;
357	MOVE SFBR TO SCRATCHE1;
358	JUMP REL(waitphase);
359datain:
360        CALL REL(savedsa);
361	MOVE SCRATCHC0 | f_c_data TO SCRATCHC0;
362	datain_loop:
363	MOVE FROM t_data, WHEN DATA_IN;
364	MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset
365	MOVE DSA0 + 8 to DSA0;
366	MOVE DSA1 + 0 to DSA1 WITH CARRY;
367	MOVE DSA2 + 0 to DSA2 WITH CARRY;
368	MOVE DSA3 + 0 to DSA3 WITH CARRY;
369	JUMP REL(datain_loop), WHEN DATA_IN;
370	CALL REL(restoredsa);
371	MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0;
372	JUMP REL(waitphase);
373
374dataout:
375        CALL REL(savedsa);
376	MOVE SCRATCHC0 | f_c_data TO SCRATCHC0;
377dataout_loop:
378	MOVE FROM t_data, WHEN DATA_OUT;
379	MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset
380	MOVE DSA0 + 8 to DSA0;
381	MOVE DSA1 + 0 to DSA1 WITH CARRY;
382	MOVE DSA2 + 0 to DSA2 WITH CARRY;
383	MOVE DSA3 + 0 to DSA3 WITH CARRY;
384	JUMP REL(dataout_loop), WHEN DATA_OUT;
385	CALL REL(restoredsa);
386	MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0;
387	JUMP REL(waitphase);
388
389savedsa:
390        MOVE DSA0 to SFBR;
391	MOVE SFBR to SCRATCHB0;       
392	MOVE DSA1 to SFBR;
393	MOVE SFBR to SCRATCHB1;       
394	MOVE DSA2 to SFBR;
395	MOVE SFBR to SCRATCHB2;
396	MOVE DSA3 to SFBR;
397	MOVE SFBR to SCRATCHB3;
398	RETURN;
399
400restoredsa:
401	MOVE SCRATCHB0 TO SFBR;
402	MOVE SFBR TO DSA0;
403	MOVE SCRATCHB1 TO SFBR;
404	MOVE SFBR TO DSA1;
405	MOVE SCRATCHB2 TO SFBR;
406	MOVE SFBR TO DSA2;
407	MOVE SCRATCHB3 TO SFBR;       
408	MOVE SFBR TO DSA3;
409	RETURN;
410
411disconnect:
412        MOVE SCNTL2 & 0x7f TO SCNTL2;
413	CLEAR ATN;
414	CLEAR ACK;
415	WAIT DISCONNECT;
416	RETURN;
417
418handle_extin:
419	CLEAR ACK;
420	MOVE FROM t_ext_msg_in, WHEN MSG_IN;
421	INT int_extmsgin; /* let host fill in t_ext_msg_data */
422get_extmsgdata:
423	CLEAR ACK;
424	MOVE FROM t_ext_msg_data, WHEN MSG_IN;
425	INT int_extmsgdata; 
426
427PROC esiop_led_on:
428	MOVE GPREG & 0xfe TO GPREG;
429
430PROC esiop_led_off:
431	MOVE GPREG | 0x01 TO GPREG;
432