diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/53c7xx.scr |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/53c7xx.scr')
-rw-r--r-- | drivers/scsi/53c7xx.scr | 1591 |
1 files changed, 1591 insertions, 0 deletions
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr new file mode 100644 index 000000000000..9c5694a2da8a --- /dev/null +++ b/drivers/scsi/53c7xx.scr | |||
@@ -0,0 +1,1591 @@ | |||
1 | #undef DEBUG | ||
2 | #undef EVENTS | ||
3 | #undef NO_SELECTION_TIMEOUT | ||
4 | #define BIG_ENDIAN | ||
5 | |||
6 | ; 53c710 driver. Modified from Drew Eckhardts driver | ||
7 | ; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk] | ||
8 | ; | ||
9 | ; I have left the script for the 53c8xx family in here, as it is likely | ||
10 | ; to be useful to see what I changed when bug hunting. | ||
11 | |||
12 | ; NCR 53c810 driver, main script | ||
13 | ; Sponsored by | ||
14 | ; iX Multiuser Multitasking Magazine | ||
15 | ; hm@ix.de | ||
16 | ; | ||
17 | ; Copyright 1993, 1994, 1995 Drew Eckhardt | ||
18 | ; Visionary Computing | ||
19 | ; (Unix and Linux consulting and custom programming) | ||
20 | ; drew@PoohSticks.ORG | ||
21 | ; +1 (303) 786-7975 | ||
22 | ; | ||
23 | ; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation. | ||
24 | ; | ||
25 | ; PRE-ALPHA | ||
26 | ; | ||
27 | ; For more information, please consult | ||
28 | ; | ||
29 | ; NCR 53C810 | ||
30 | ; PCI-SCSI I/O Processor | ||
31 | ; Data Manual | ||
32 | ; | ||
33 | ; NCR 53C710 | ||
34 | ; SCSI I/O Processor | ||
35 | ; Programmers Guide | ||
36 | ; | ||
37 | ; NCR Microelectronics | ||
38 | ; 1635 Aeroplaza Drive | ||
39 | ; Colorado Springs, CO 80916 | ||
40 | ; 1+ (719) 578-3400 | ||
41 | ; | ||
42 | ; Toll free literature number | ||
43 | ; +1 (800) 334-5454 | ||
44 | ; | ||
45 | ; IMPORTANT : This code is self modifying due to the limitations of | ||
46 | ; the NCR53c7,8xx series chips. Persons debugging this code with | ||
47 | ; the remote debugger should take this into account, and NOT set | ||
48 | ; breakpoints in modified instructions. | ||
49 | ; | ||
50 | ; Design: | ||
51 | ; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard | ||
52 | ; microcontroller using a simple instruction set. | ||
53 | ; | ||
54 | ; So, to minimize the effects of interrupt latency, and to maximize | ||
55 | ; throughput, this driver offloads the practical maximum amount | ||
56 | ; of processing to the SCSI chip while still maintaining a common | ||
57 | ; structure. | ||
58 | ; | ||
59 | ; Where tradeoffs were needed between efficiency on the older | ||
60 | ; chips and the newer NCR53c800 series, the NCR53c800 series | ||
61 | ; was chosen. | ||
62 | ; | ||
63 | ; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully | ||
64 | ; automate SCSI transfers without host processor intervention, this | ||
65 | ; isn't the case with the NCR53c710 and newer chips which allow | ||
66 | ; | ||
67 | ; - reads and writes to the internal registers from within the SCSI | ||
68 | ; scripts, allowing the SCSI SCRIPTS(tm) code to save processor | ||
69 | ; state so that multiple threads of execution are possible, and also | ||
70 | ; provide an ALU for loop control, etc. | ||
71 | ; | ||
72 | ; - table indirect addressing for some instructions. This allows | ||
73 | ; pointers to be located relative to the DSA ((Data Structure | ||
74 | ; Address) register. | ||
75 | ; | ||
76 | ; These features make it possible to implement a mailbox style interface, | ||
77 | ; where the same piece of code is run to handle I/O for multiple threads | ||
78 | ; at once minimizing our need to relocate code. Since the NCR53c700/ | ||
79 | ; NCR53c800 series have a unique combination of features, making a | ||
80 | ; a standard ingoing/outgoing mailbox system, costly, I've modified it. | ||
81 | ; | ||
82 | ; - Mailboxes are a mixture of code and data. This lets us greatly | ||
83 | ; simplify the NCR53c810 code and do things that would otherwise | ||
84 | ; not be possible. | ||
85 | ; | ||
86 | ; The saved data pointer is now implemented as follows : | ||
87 | ; | ||
88 | ; Control flow has been architected such that if control reaches | ||
89 | ; munge_save_data_pointer, on a restore pointers message or | ||
90 | ; reconnection, a jump to the address formerly in the TEMP register | ||
91 | ; will allow the SCSI command to resume execution. | ||
92 | ; | ||
93 | |||
94 | ; | ||
95 | ; Note : the DSA structures must be aligned on 32 bit boundaries, | ||
96 | ; since the source and destination of MOVE MEMORY instructions | ||
97 | ; must share the same alignment and this is the alignment of the | ||
98 | ; NCR registers. | ||
99 | ; | ||
100 | |||
101 | ; For some systems (MVME166, for example) dmode is always the same, so don't | ||
102 | ; waste time writing it | ||
103 | |||
104 | #if 1 | ||
105 | #define DMODE_MEMORY_TO_NCR | ||
106 | #define DMODE_MEMORY_TO_MEMORY | ||
107 | #define DMODE_NCR_TO_MEMORY | ||
108 | #else | ||
109 | #define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE | ||
110 | #define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE | ||
111 | #define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE | ||
112 | #endif | ||
113 | |||
114 | ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa | ||
115 | ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa | ||
116 | ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address | ||
117 | ; for current dsa | ||
118 | ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target | ||
119 | ; sync routine | ||
120 | ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target | ||
121 | ; sscf value (53c710) | ||
122 | ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa | ||
123 | ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command | ||
124 | ; saved data pointer | ||
125 | ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command | ||
126 | ; current residual code | ||
127 | ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command | ||
128 | ; saved residual code | ||
129 | ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand | ||
130 | ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to | ||
131 | ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value | ||
132 | |||
133 | ; | ||
134 | ; Once a device has initiated reselection, we need to compare it | ||
135 | ; against the singly linked list of commands which have disconnected | ||
136 | ; and are pending reselection. These commands are maintained in | ||
137 | ; an unordered singly linked list of DSA structures, through the | ||
138 | ; DSA pointers at their 'centers' headed by the reconnect_dsa_head | ||
139 | ; pointer. | ||
140 | ; | ||
141 | ; To avoid complications in removing commands from the list, | ||
142 | ; I minimize the amount of expensive (at eight operations per | ||
143 | ; addition @ 500-600ns each) pointer operations which must | ||
144 | ; be done in the NCR driver by precomputing them on the | ||
145 | ; host processor during dsa structure generation. | ||
146 | ; | ||
147 | ; The fixed-up per DSA code knows how to recognize the nexus | ||
148 | ; associated with the corresponding SCSI command, and modifies | ||
149 | ; the source and destination pointers for the MOVE MEMORY | ||
150 | ; instruction which is executed when reselected_ok is called | ||
151 | ; to remove the command from the list. Similarly, DSA is | ||
152 | ; loaded with the address of the next DSA structure and | ||
153 | ; reselected_check_next is called if a failure occurs. | ||
154 | ; | ||
155 | ; Perhaps more concisely, the net effect of the mess is | ||
156 | ; | ||
157 | ; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, | ||
158 | ; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) { | ||
159 | ; src = &dsa->next; | ||
160 | ; if (target_id == dsa->id && target_lun == dsa->lun) { | ||
161 | ; *dest = *src; | ||
162 | ; break; | ||
163 | ; } | ||
164 | ; } | ||
165 | ; | ||
166 | ; if (!dsa) | ||
167 | ; error (int_err_unexpected_reselect); | ||
168 | ; else | ||
169 | ; longjmp (dsa->jump_resume, 0); | ||
170 | ; | ||
171 | ; | ||
172 | |||
173 | #if (CHIP != 700) && (CHIP != 70066) | ||
174 | ; Define DSA structure used for mailboxes | ||
175 | ENTRY dsa_code_template | ||
176 | dsa_code_template: | ||
177 | ENTRY dsa_code_begin | ||
178 | dsa_code_begin: | ||
179 | ; RGH: Don't care about TEMP and DSA here | ||
180 | DMODE_MEMORY_TO_NCR | ||
181 | MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch | ||
182 | DMODE_MEMORY_TO_MEMORY | ||
183 | #if (CHIP == 710) | ||
184 | MOVE MEMORY 4, addr_scratch, saved_dsa | ||
185 | ; We are about to go and select the device, so must set SSCF bits | ||
186 | MOVE MEMORY 4, dsa_sscf_710, addr_scratch | ||
187 | #ifdef BIG_ENDIAN | ||
188 | MOVE SCRATCH3 TO SFBR | ||
189 | #else | ||
190 | MOVE SCRATCH0 TO SFBR | ||
191 | #endif | ||
192 | MOVE SFBR TO SBCL | ||
193 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
194 | #else | ||
195 | CALL scratch_to_dsa | ||
196 | #endif | ||
197 | CALL select | ||
198 | ; Handle the phase mismatch which may have resulted from the | ||
199 | ; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN | ||
200 | ; may or may not be necessary, and we should update script_asm.pl | ||
201 | ; to handle multiple pieces. | ||
202 | CLEAR ATN | ||
203 | CLEAR ACK | ||
204 | |||
205 | ; Replace second operand with address of JUMP instruction dest operand | ||
206 | ; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c. | ||
207 | ENTRY dsa_code_fix_jump | ||
208 | dsa_code_fix_jump: | ||
209 | MOVE MEMORY 4, NOP_insn, 0 | ||
210 | JUMP select_done | ||
211 | |||
212 | ; wrong_dsa loads the DSA register with the value of the dsa_next | ||
213 | ; field. | ||
214 | ; | ||
215 | wrong_dsa: | ||
216 | #if (CHIP == 710) | ||
217 | ; NOTE DSA is corrupt when we arrive here! | ||
218 | #endif | ||
219 | ; Patch the MOVE MEMORY INSTRUCTION such that | ||
220 | ; the destination address is the address of the OLD | ||
221 | ; next pointer. | ||
222 | ; | ||
223 | MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8 | ||
224 | DMODE_MEMORY_TO_NCR | ||
225 | ; | ||
226 | ; Move the _contents_ of the next pointer into the DSA register as | ||
227 | ; the next I_T_L or I_T_L_Q tupple to check against the established | ||
228 | ; nexus. | ||
229 | ; | ||
230 | MOVE MEMORY 4, dsa_temp_next, addr_scratch | ||
231 | DMODE_MEMORY_TO_MEMORY | ||
232 | #if (CHIP == 710) | ||
233 | MOVE MEMORY 4, addr_scratch, saved_dsa | ||
234 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
235 | #else | ||
236 | CALL scratch_to_dsa | ||
237 | #endif | ||
238 | JUMP reselected_check_next | ||
239 | |||
240 | ABSOLUTE dsa_save_data_pointer = 0 | ||
241 | ENTRY dsa_code_save_data_pointer | ||
242 | dsa_code_save_data_pointer: | ||
243 | #if (CHIP == 710) | ||
244 | ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt | ||
245 | ; We MUST return with DSA correct | ||
246 | MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer | ||
247 | ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h | ||
248 | MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual | ||
249 | CLEAR ACK | ||
250 | #ifdef DEBUG | ||
251 | INT int_debug_saved | ||
252 | #endif | ||
253 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
254 | JUMP jump_temp | ||
255 | #else | ||
256 | DMODE_NCR_TO_MEMORY | ||
257 | MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer | ||
258 | DMODE_MEMORY_TO_MEMORY | ||
259 | ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h | ||
260 | MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual | ||
261 | CLEAR ACK | ||
262 | #ifdef DEBUG | ||
263 | INT int_debug_saved | ||
264 | #endif | ||
265 | RETURN | ||
266 | #endif | ||
267 | ABSOLUTE dsa_restore_pointers = 0 | ||
268 | ENTRY dsa_code_restore_pointers | ||
269 | dsa_code_restore_pointers: | ||
270 | #if (CHIP == 710) | ||
271 | ; TEMP and DSA are corrupt when we get here, but who cares! | ||
272 | MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4 | ||
273 | ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h | ||
274 | MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual | ||
275 | CLEAR ACK | ||
276 | ; Restore DSA, note we don't care about TEMP | ||
277 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
278 | #ifdef DEBUG | ||
279 | INT int_debug_restored | ||
280 | #endif | ||
281 | JUMP jump_temp | ||
282 | #else | ||
283 | DMODE_MEMORY_TO_NCR | ||
284 | MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp | ||
285 | DMODE_MEMORY_TO_MEMORY | ||
286 | ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h | ||
287 | MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual | ||
288 | CLEAR ACK | ||
289 | #ifdef DEBUG | ||
290 | INT int_debug_restored | ||
291 | #endif | ||
292 | RETURN | ||
293 | #endif | ||
294 | |||
295 | ABSOLUTE dsa_check_reselect = 0 | ||
296 | ; dsa_check_reselect determines whether or not the current target and | ||
297 | ; lun match the current DSA | ||
298 | ENTRY dsa_code_check_reselect | ||
299 | dsa_code_check_reselect: | ||
300 | #if (CHIP == 710) | ||
301 | /* Arrives here with DSA correct */ | ||
302 | /* Assumes we are always ID 7 */ | ||
303 | MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set | ||
304 | JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80 | ||
305 | #else | ||
306 | MOVE SSID TO SFBR ; SSID contains 3 bit target ID | ||
307 | ; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips | ||
308 | JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8 | ||
309 | #endif | ||
310 | ; | ||
311 | ; Hack - move to scratch first, since SFBR is not writeable | ||
312 | ; via the CPU and hence a MOVE MEMORY instruction. | ||
313 | ; | ||
314 | DMODE_MEMORY_TO_NCR | ||
315 | MOVE MEMORY 1, reselected_identify, addr_scratch | ||
316 | DMODE_MEMORY_TO_MEMORY | ||
317 | #ifdef BIG_ENDIAN | ||
318 | ; BIG ENDIAN ON MVME16x | ||
319 | MOVE SCRATCH3 TO SFBR | ||
320 | #else | ||
321 | MOVE SCRATCH0 TO SFBR | ||
322 | #endif | ||
323 | ; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips | ||
324 | ; Are you sure about that? richard@sleepie.demon.co.uk | ||
325 | JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8 | ||
326 | ; Patch the MOVE MEMORY INSTRUCTION such that | ||
327 | ; the source address is the address of this dsa's | ||
328 | ; next pointer. | ||
329 | MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4 | ||
330 | CALL reselected_ok | ||
331 | #if (CHIP == 710) | ||
332 | ; Restore DSA following memory moves in reselected_ok | ||
333 | ; dsa_temp_sync doesn't really care about DSA, but it has an | ||
334 | ; optional debug INT so a valid DSA is a good idea. | ||
335 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
336 | #endif | ||
337 | CALL dsa_temp_sync | ||
338 | ; Release ACK on the IDENTIFY message _after_ we've set the synchronous | ||
339 | ; transfer parameters! | ||
340 | CLEAR ACK | ||
341 | ; Implicitly restore pointers on reselection, so a RETURN | ||
342 | ; will transfer control back to the right spot. | ||
343 | CALL REL (dsa_code_restore_pointers) | ||
344 | RETURN | ||
345 | ENTRY dsa_zero | ||
346 | dsa_zero: | ||
347 | ENTRY dsa_code_template_end | ||
348 | dsa_code_template_end: | ||
349 | |||
350 | ; Perform sanity check for dsa_fields_start == dsa_code_template_end - | ||
351 | ; dsa_zero, puke. | ||
352 | |||
353 | ABSOLUTE dsa_fields_start = 0 ; Sanity marker | ||
354 | ; pad 48 bytes (fix this RSN) | ||
355 | ABSOLUTE dsa_next = 48 ; len 4 Next DSA | ||
356 | ; del 4 Previous DSA address | ||
357 | ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread. | ||
358 | ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for | ||
359 | ; table indirect select | ||
360 | ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for | ||
361 | ; select message | ||
362 | ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for | ||
363 | ; command | ||
364 | ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout | ||
365 | ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain | ||
366 | ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin | ||
367 | ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte | ||
368 | ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out | ||
369 | ; (Synchronous transfer negotiation, etc). | ||
370 | ABSOLUTE dsa_end = 112 | ||
371 | |||
372 | ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next), | ||
373 | ; terminated by a call to JUMP wait_reselect | ||
374 | |||
375 | ; Linked lists of DSA structures | ||
376 | ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect | ||
377 | ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing | ||
378 | ; address of reconnect_dsa_head | ||
379 | |||
380 | ; These select the source and destination of a MOVE MEMORY instruction | ||
381 | ABSOLUTE dmode_memory_to_memory = 0x0 | ||
382 | ABSOLUTE dmode_memory_to_ncr = 0x0 | ||
383 | ABSOLUTE dmode_ncr_to_memory = 0x0 | ||
384 | |||
385 | ABSOLUTE addr_scratch = 0x0 | ||
386 | ABSOLUTE addr_temp = 0x0 | ||
387 | #if (CHIP == 710) | ||
388 | ABSOLUTE saved_dsa = 0x0 | ||
389 | ABSOLUTE emulfly = 0x0 | ||
390 | ABSOLUTE addr_dsa = 0x0 | ||
391 | #endif | ||
392 | #endif /* CHIP != 700 && CHIP != 70066 */ | ||
393 | |||
394 | ; Interrupts - | ||
395 | ; MSB indicates type | ||
396 | ; 0 handle error condition | ||
397 | ; 1 handle message | ||
398 | ; 2 handle normal condition | ||
399 | ; 3 debugging interrupt | ||
400 | ; 4 testing interrupt | ||
401 | ; Next byte indicates specific error | ||
402 | |||
403 | ; XXX not yet implemented, I'm not sure if I want to - | ||
404 | ; Next byte indicates the routine the error occurred in | ||
405 | ; The LSB indicates the specific place the error occurred | ||
406 | |||
407 | ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered | ||
408 | ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED) | ||
409 | ABSOLUTE int_err_unexpected_reselect = 0x00020000 | ||
410 | ABSOLUTE int_err_check_condition = 0x00030000 | ||
411 | ABSOLUTE int_err_no_phase = 0x00040000 | ||
412 | ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received | ||
413 | ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received | ||
414 | ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message | ||
415 | ; received | ||
416 | |||
417 | ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram | ||
418 | ; registers. | ||
419 | ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established | ||
420 | ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete | ||
421 | ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected | ||
422 | ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa | ||
423 | ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset. | ||
424 | ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly | ||
425 | ABSOLUTE int_debug_break = 0x03000000 ; Break point | ||
426 | #ifdef DEBUG | ||
427 | ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled | ||
428 | ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle | ||
429 | ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded | ||
430 | ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected | ||
431 | ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten | ||
432 | ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected | ||
433 | ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect | ||
434 | ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule | ||
435 | ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA | ||
436 | ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted | ||
437 | #endif | ||
438 | ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver | ||
439 | #ifdef DEBUG | ||
440 | ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers | ||
441 | ABSOLUTE int_debug_restored = 0x030d0000 | ||
442 | ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous | ||
443 | ; parameters. | ||
444 | ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase | ||
445 | ; now. | ||
446 | ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against | ||
447 | ; SDID. | ||
448 | #endif | ||
449 | |||
450 | ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete | ||
451 | ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete | ||
452 | ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete | ||
453 | |||
454 | |||
455 | ; These should start with 0x05000000, with low bits incrementing for | ||
456 | ; each one. | ||
457 | |||
458 | #ifdef EVENTS | ||
459 | ABSOLUTE int_EVENT_SELECT = 0 | ||
460 | ABSOLUTE int_EVENT_DISCONNECT = 0 | ||
461 | ABSOLUTE int_EVENT_RESELECT = 0 | ||
462 | ABSOLUTE int_EVENT_COMPLETE = 0 | ||
463 | ABSOLUTE int_EVENT_IDLE = 0 | ||
464 | ABSOLUTE int_EVENT_SELECT_FAILED = 0 | ||
465 | ABSOLUTE int_EVENT_BEFORE_SELECT = 0 | ||
466 | ABSOLUTE int_EVENT_RESELECT_FAILED = 0 | ||
467 | #endif | ||
468 | |||
469 | ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message | ||
470 | ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message | ||
471 | ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source | ||
472 | ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in | ||
473 | ABSOLUTE NOP_insn = 0 ; NOP instruction | ||
474 | |||
475 | ; Pointer to message, potentially multi-byte | ||
476 | ABSOLUTE msg_buf = 0 | ||
477 | |||
478 | ; Pointer to holding area for reselection information | ||
479 | ABSOLUTE reselected_identify = 0 | ||
480 | ABSOLUTE reselected_tag = 0 | ||
481 | |||
482 | ; Request sense command pointer, it's a 6 byte command, should | ||
483 | ; be constant for all commands since we always want 16 bytes of | ||
484 | ; sense and we don't need to change any fields as we did under | ||
485 | ; SCSI-I when we actually cared about the LUN field. | ||
486 | ;EXTERNAL NCR53c7xx_sense ; Request sense command | ||
487 | |||
488 | #if (CHIP != 700) && (CHIP != 70066) | ||
489 | ; dsa_schedule | ||
490 | ; PURPOSE : after a DISCONNECT message has been received, and pointers | ||
491 | ; saved, insert the current DSA structure at the head of the | ||
492 | ; disconnected queue and fall through to the scheduler. | ||
493 | ; | ||
494 | ; CALLS : OK | ||
495 | ; | ||
496 | ; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list | ||
497 | ; of disconnected commands | ||
498 | ; | ||
499 | ; MODIFIES : SCRATCH, reconnect_dsa_head | ||
500 | ; | ||
501 | ; EXITS : always passes control to schedule | ||
502 | |||
503 | ENTRY dsa_schedule | ||
504 | dsa_schedule: | ||
505 | #ifdef DEBUG | ||
506 | INT int_debug_dsa_schedule | ||
507 | #endif | ||
508 | |||
509 | ; | ||
510 | ; Calculate the address of the next pointer within the DSA | ||
511 | ; structure of the command that is currently disconnecting | ||
512 | ; | ||
513 | #if (CHIP == 710) | ||
514 | ; Read what should be the current DSA from memory - actual DSA | ||
515 | ; register is probably corrupt | ||
516 | MOVE MEMORY 4, saved_dsa, addr_scratch | ||
517 | #else | ||
518 | CALL dsa_to_scratch | ||
519 | #endif | ||
520 | MOVE SCRATCH0 + dsa_next TO SCRATCH0 | ||
521 | MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY | ||
522 | MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY | ||
523 | MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY | ||
524 | |||
525 | ; Point the next field of this DSA structure at the current disconnected | ||
526 | ; list | ||
527 | DMODE_NCR_TO_MEMORY | ||
528 | MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8 | ||
529 | DMODE_MEMORY_TO_MEMORY | ||
530 | dsa_schedule_insert: | ||
531 | MOVE MEMORY 4, reconnect_dsa_head, 0 | ||
532 | |||
533 | ; And update the head pointer. | ||
534 | #if (CHIP == 710) | ||
535 | ; Read what should be the current DSA from memory - actual DSA | ||
536 | ; register is probably corrupt | ||
537 | MOVE MEMORY 4, saved_dsa, addr_scratch | ||
538 | #else | ||
539 | CALL dsa_to_scratch | ||
540 | #endif | ||
541 | DMODE_NCR_TO_MEMORY | ||
542 | MOVE MEMORY 4, addr_scratch, reconnect_dsa_head | ||
543 | DMODE_MEMORY_TO_MEMORY | ||
544 | /* Temporarily, see what happens. */ | ||
545 | #ifndef ORIGINAL | ||
546 | #if (CHIP != 710) | ||
547 | MOVE SCNTL2 & 0x7f TO SCNTL2 | ||
548 | #endif | ||
549 | CLEAR ACK | ||
550 | #endif | ||
551 | #if (CHIP == 710) | ||
552 | ; Time to correct DSA following memory move | ||
553 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
554 | #endif | ||
555 | WAIT DISCONNECT | ||
556 | #ifdef EVENTS | ||
557 | INT int_EVENT_DISCONNECT; | ||
558 | #endif | ||
559 | #ifdef DEBUG | ||
560 | INT int_debug_disconnected | ||
561 | #endif | ||
562 | JUMP schedule | ||
563 | #endif | ||
564 | |||
565 | ; | ||
566 | ; select | ||
567 | ; | ||
568 | ; PURPOSE : establish a nexus for the SCSI command referenced by DSA. | ||
569 | ; On success, the current DSA structure is removed from the issue | ||
570 | ; queue. Usually, this is entered as a fall-through from schedule, | ||
571 | ; although the contingent allegiance handling code will write | ||
572 | ; the select entry address to the DSP to restart a command as a | ||
573 | ; REQUEST SENSE. A message is sent (usually IDENTIFY, although | ||
574 | ; additional SDTR or WDTR messages may be sent). COMMAND OUT | ||
575 | ; is handled. | ||
576 | ; | ||
577 | ; INPUTS : DSA - SCSI command, issue_dsa_head | ||
578 | ; | ||
579 | ; CALLS : NOT OK | ||
580 | ; | ||
581 | ; MODIFIES : SCRATCH, issue_dsa_head | ||
582 | ; | ||
583 | ; EXITS : on reselection or selection, go to select_failed | ||
584 | ; otherwise, RETURN so control is passed back to | ||
585 | ; dsa_begin. | ||
586 | ; | ||
587 | |||
588 | ENTRY select | ||
589 | select: | ||
590 | |||
591 | #ifdef EVENTS | ||
592 | INT int_EVENT_BEFORE_SELECT | ||
593 | #endif | ||
594 | |||
595 | #ifdef DEBUG | ||
596 | INT int_debug_scheduled | ||
597 | #endif | ||
598 | CLEAR TARGET | ||
599 | |||
600 | ; XXX | ||
601 | ; | ||
602 | ; In effect, SELECTION operations are backgrounded, with execution | ||
603 | ; continuing until code which waits for REQ or a fatal interrupt is | ||
604 | ; encountered. | ||
605 | ; | ||
606 | ; So, for more performance, we could overlap the code which removes | ||
607 | ; the command from the NCRs issue queue with the selection, but | ||
608 | ; at this point I don't want to deal with the error recovery. | ||
609 | ; | ||
610 | |||
611 | #if (CHIP != 700) && (CHIP != 70066) | ||
612 | #if (CHIP == 710) | ||
613 | ; Enable selection timer | ||
614 | #ifdef NO_SELECTION_TIMEOUT | ||
615 | MOVE CTEST7 & 0xff TO CTEST7 | ||
616 | #else | ||
617 | MOVE CTEST7 & 0xef TO CTEST7 | ||
618 | #endif | ||
619 | #endif | ||
620 | SELECT ATN FROM dsa_select, select_failed | ||
621 | JUMP select_msgout, WHEN MSG_OUT | ||
622 | ENTRY select_msgout | ||
623 | select_msgout: | ||
624 | #if (CHIP == 710) | ||
625 | ; Disable selection timer | ||
626 | MOVE CTEST7 | 0x10 TO CTEST7 | ||
627 | #endif | ||
628 | MOVE FROM dsa_msgout, WHEN MSG_OUT | ||
629 | #else | ||
630 | ENTRY select_msgout | ||
631 | SELECT ATN 0, select_failed | ||
632 | select_msgout: | ||
633 | MOVE 0, 0, WHEN MSGOUT | ||
634 | #endif | ||
635 | |||
636 | #ifdef EVENTS | ||
637 | INT int_EVENT_SELECT | ||
638 | #endif | ||
639 | RETURN | ||
640 | |||
641 | ; | ||
642 | ; select_done | ||
643 | ; | ||
644 | ; PURPOSE: continue on to normal data transfer; called as the exit | ||
645 | ; point from dsa_begin. | ||
646 | ; | ||
647 | ; INPUTS: dsa | ||
648 | ; | ||
649 | ; CALLS: OK | ||
650 | ; | ||
651 | ; | ||
652 | |||
653 | select_done: | ||
654 | #if (CHIP == 710) | ||
655 | ; NOTE DSA is corrupt when we arrive here! | ||
656 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
657 | #endif | ||
658 | |||
659 | #ifdef DEBUG | ||
660 | ENTRY select_check_dsa | ||
661 | select_check_dsa: | ||
662 | INT int_debug_check_dsa | ||
663 | #endif | ||
664 | |||
665 | ; After a successful selection, we should get either a CMD phase or | ||
666 | ; some transfer request negotiation message. | ||
667 | |||
668 | JUMP cmdout, WHEN CMD | ||
669 | INT int_err_unexpected_phase, WHEN NOT MSG_IN | ||
670 | |||
671 | select_msg_in: | ||
672 | CALL msg_in, WHEN MSG_IN | ||
673 | JUMP select_msg_in, WHEN MSG_IN | ||
674 | |||
675 | cmdout: | ||
676 | INT int_err_unexpected_phase, WHEN NOT CMD | ||
677 | #if (CHIP == 700) | ||
678 | INT int_norm_selected | ||
679 | #endif | ||
680 | ENTRY cmdout_cmdout | ||
681 | cmdout_cmdout: | ||
682 | #if (CHIP != 700) && (CHIP != 70066) | ||
683 | MOVE FROM dsa_cmdout, WHEN CMD | ||
684 | #else | ||
685 | MOVE 0, 0, WHEN CMD | ||
686 | #endif /* (CHIP != 700) && (CHIP != 70066) */ | ||
687 | |||
688 | ; | ||
689 | ; data_transfer | ||
690 | ; other_out | ||
691 | ; other_in | ||
692 | ; other_transfer | ||
693 | ; | ||
694 | ; PURPOSE : handle the main data transfer for a SCSI command in | ||
695 | ; several parts. In the first part, data_transfer, DATA_IN | ||
696 | ; and DATA_OUT phases are allowed, with the user provided | ||
697 | ; code (usually dynamically generated based on the scatter/gather | ||
698 | ; list associated with a SCSI command) called to handle these | ||
699 | ; phases. | ||
700 | ; | ||
701 | ; After control has passed to one of the user provided | ||
702 | ; DATA_IN or DATA_OUT routines, back calls are made to | ||
703 | ; other_transfer_in or other_transfer_out to handle non-DATA IN | ||
704 | ; and DATA OUT phases respectively, with the state of the active | ||
705 | ; data pointer being preserved in TEMP. | ||
706 | ; | ||
707 | ; On completion, the user code passes control to other_transfer | ||
708 | ; which causes DATA_IN and DATA_OUT to result in unexpected_phase | ||
709 | ; interrupts so that data overruns may be trapped. | ||
710 | ; | ||
711 | ; INPUTS : DSA - SCSI command | ||
712 | ; | ||
713 | ; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in | ||
714 | ; other_transfer | ||
715 | ; | ||
716 | ; MODIFIES : SCRATCH | ||
717 | ; | ||
718 | ; EXITS : if STATUS IN is detected, signifying command completion, | ||
719 | ; the NCR jumps to command_complete. If MSG IN occurs, a | ||
720 | ; CALL is made to msg_in. Otherwise, other_transfer runs in | ||
721 | ; an infinite loop. | ||
722 | ; | ||
723 | |||
724 | ENTRY data_transfer | ||
725 | data_transfer: | ||
726 | JUMP cmdout_cmdout, WHEN CMD | ||
727 | CALL msg_in, WHEN MSG_IN | ||
728 | INT int_err_unexpected_phase, WHEN MSG_OUT | ||
729 | JUMP do_dataout, WHEN DATA_OUT | ||
730 | JUMP do_datain, WHEN DATA_IN | ||
731 | JUMP command_complete, WHEN STATUS | ||
732 | JUMP data_transfer | ||
733 | ENTRY end_data_transfer | ||
734 | end_data_transfer: | ||
735 | |||
736 | ; | ||
737 | ; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain | ||
738 | ; should be fixed up whenever the nexus changes so it can point to the | ||
739 | ; correct routine for that command. | ||
740 | ; | ||
741 | |||
742 | #if (CHIP != 700) && (CHIP != 70066) | ||
743 | ; Nasty jump to dsa->dataout | ||
744 | do_dataout: | ||
745 | #if (CHIP == 710) | ||
746 | MOVE MEMORY 4, saved_dsa, addr_scratch | ||
747 | #else | ||
748 | CALL dsa_to_scratch | ||
749 | #endif | ||
750 | MOVE SCRATCH0 + dsa_dataout TO SCRATCH0 | ||
751 | MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY | ||
752 | MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY | ||
753 | MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY | ||
754 | DMODE_NCR_TO_MEMORY | ||
755 | MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4 | ||
756 | DMODE_MEMORY_TO_MEMORY | ||
757 | dataout_to_jump: | ||
758 | MOVE MEMORY 4, 0, dataout_jump + 4 | ||
759 | #if (CHIP == 710) | ||
760 | ; Time to correct DSA following memory move | ||
761 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
762 | #endif | ||
763 | dataout_jump: | ||
764 | JUMP 0 | ||
765 | |||
766 | ; Nasty jump to dsa->dsain | ||
767 | do_datain: | ||
768 | #if (CHIP == 710) | ||
769 | MOVE MEMORY 4, saved_dsa, addr_scratch | ||
770 | #else | ||
771 | CALL dsa_to_scratch | ||
772 | #endif | ||
773 | MOVE SCRATCH0 + dsa_datain TO SCRATCH0 | ||
774 | MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY | ||
775 | MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY | ||
776 | MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY | ||
777 | DMODE_NCR_TO_MEMORY | ||
778 | MOVE MEMORY 4, addr_scratch, datain_to_jump + 4 | ||
779 | DMODE_MEMORY_TO_MEMORY | ||
780 | ENTRY datain_to_jump | ||
781 | datain_to_jump: | ||
782 | MOVE MEMORY 4, 0, datain_jump + 4 | ||
783 | #if (CHIP == 710) | ||
784 | ; Time to correct DSA following memory move | ||
785 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
786 | #endif | ||
787 | #ifdef DEBUG | ||
788 | INT int_debug_datain | ||
789 | #endif | ||
790 | datain_jump: | ||
791 | JUMP 0 | ||
792 | #endif /* (CHIP != 700) && (CHIP != 70066) */ | ||
793 | |||
794 | |||
795 | ; Note that other_out and other_in loop until a non-data phase | ||
796 | ; is discovered, so we only execute return statements when we | ||
797 | ; can go on to the next data phase block move statement. | ||
798 | |||
799 | ENTRY other_out | ||
800 | other_out: | ||
801 | #if 0 | ||
802 | INT 0x03ffdead | ||
803 | #endif | ||
804 | INT int_err_unexpected_phase, WHEN CMD | ||
805 | JUMP msg_in_restart, WHEN MSG_IN | ||
806 | INT int_err_unexpected_phase, WHEN MSG_OUT | ||
807 | INT int_err_unexpected_phase, WHEN DATA_IN | ||
808 | JUMP command_complete, WHEN STATUS | ||
809 | JUMP other_out, WHEN NOT DATA_OUT | ||
810 | #if (CHIP == 710) | ||
811 | ; TEMP should be OK, as we got here from a call in the user dataout code. | ||
812 | #endif | ||
813 | RETURN | ||
814 | |||
815 | ENTRY other_in | ||
816 | other_in: | ||
817 | #if 0 | ||
818 | INT 0x03ffdead | ||
819 | #endif | ||
820 | INT int_err_unexpected_phase, WHEN CMD | ||
821 | JUMP msg_in_restart, WHEN MSG_IN | ||
822 | INT int_err_unexpected_phase, WHEN MSG_OUT | ||
823 | INT int_err_unexpected_phase, WHEN DATA_OUT | ||
824 | JUMP command_complete, WHEN STATUS | ||
825 | JUMP other_in, WHEN NOT DATA_IN | ||
826 | #if (CHIP == 710) | ||
827 | ; TEMP should be OK, as we got here from a call in the user datain code. | ||
828 | #endif | ||
829 | RETURN | ||
830 | |||
831 | |||
832 | ENTRY other_transfer | ||
833 | other_transfer: | ||
834 | INT int_err_unexpected_phase, WHEN CMD | ||
835 | CALL msg_in, WHEN MSG_IN | ||
836 | INT int_err_unexpected_phase, WHEN MSG_OUT | ||
837 | INT int_err_unexpected_phase, WHEN DATA_OUT | ||
838 | INT int_err_unexpected_phase, WHEN DATA_IN | ||
839 | JUMP command_complete, WHEN STATUS | ||
840 | JUMP other_transfer | ||
841 | |||
842 | ; | ||
843 | ; msg_in_restart | ||
844 | ; msg_in | ||
845 | ; munge_msg | ||
846 | ; | ||
847 | ; PURPOSE : process messages from a target. msg_in is called when the | ||
848 | ; caller hasn't read the first byte of the message. munge_message | ||
849 | ; is called when the caller has read the first byte of the message, | ||
850 | ; and left it in SFBR. msg_in_restart is called when the caller | ||
851 | ; hasn't read the first byte of the message, and wishes RETURN | ||
852 | ; to transfer control back to the address of the conditional | ||
853 | ; CALL instruction rather than to the instruction after it. | ||
854 | ; | ||
855 | ; Various int_* interrupts are generated when the host system | ||
856 | ; needs to intervene, as is the case with SDTR, WDTR, and | ||
857 | ; INITIATE RECOVERY messages. | ||
858 | ; | ||
859 | ; When the host system handles one of these interrupts, | ||
860 | ; it can respond by reentering at reject_message, | ||
861 | ; which rejects the message and returns control to | ||
862 | ; the caller of msg_in or munge_msg, accept_message | ||
863 | ; which clears ACK and returns control, or reply_message | ||
864 | ; which sends the message pointed to by the DSA | ||
865 | ; msgout_other table indirect field. | ||
866 | ; | ||
867 | ; DISCONNECT messages are handled by moving the command | ||
868 | ; to the reconnect_dsa_queue. | ||
869 | #if (CHIP == 710) | ||
870 | ; NOTE: DSA should be valid when we get here - we cannot save both it | ||
871 | ; and TEMP in this routine. | ||
872 | #endif | ||
873 | ; | ||
874 | ; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg | ||
875 | ; only) | ||
876 | ; | ||
877 | ; CALLS : NO. The TEMP register isn't backed up to allow nested calls. | ||
878 | ; | ||
879 | ; MODIFIES : SCRATCH, DSA on DISCONNECT | ||
880 | ; | ||
881 | ; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS, | ||
882 | ; and normal return from message handlers running under | ||
883 | ; Linux, control is returned to the caller. Receipt | ||
884 | ; of DISCONNECT messages pass control to dsa_schedule. | ||
885 | ; | ||
886 | ENTRY msg_in_restart | ||
887 | msg_in_restart: | ||
888 | ; XXX - hackish | ||
889 | ; | ||
890 | ; Since it's easier to debug changes to the statically | ||
891 | ; compiled code, rather than the dynamically generated | ||
892 | ; stuff, such as | ||
893 | ; | ||
894 | ; MOVE x, y, WHEN data_phase | ||
895 | ; CALL other_z, WHEN NOT data_phase | ||
896 | ; MOVE x, y, WHEN data_phase | ||
897 | ; | ||
898 | ; I'd like to have certain routines (notably the message handler) | ||
899 | ; restart on the conditional call rather than the next instruction. | ||
900 | ; | ||
901 | ; So, subtract 8 from the return address | ||
902 | |||
903 | MOVE TEMP0 + 0xf8 TO TEMP0 | ||
904 | MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY | ||
905 | MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY | ||
906 | MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY | ||
907 | |||
908 | ENTRY msg_in | ||
909 | msg_in: | ||
910 | MOVE 1, msg_buf, WHEN MSG_IN | ||
911 | |||
912 | munge_msg: | ||
913 | JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE | ||
914 | JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message | ||
915 | ; | ||
916 | ; XXX - I've seen a handful of broken SCSI devices which fail to issue | ||
917 | ; a SAVE POINTERS message before disconnecting in the middle of | ||
918 | ; a transfer, assuming that the DATA POINTER will be implicitly | ||
919 | ; restored. | ||
920 | ; | ||
921 | ; Historically, I've often done an implicit save when the DISCONNECT | ||
922 | ; message is processed. We may want to consider having the option of | ||
923 | ; doing that here. | ||
924 | ; | ||
925 | JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER | ||
926 | JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS | ||
927 | JUMP munge_disconnect, IF 0x04 ; DISCONNECT | ||
928 | INT int_msg_1, IF 0x07 ; MESSAGE REJECT | ||
929 | INT int_msg_1, IF 0x0f ; INITIATE RECOVERY | ||
930 | #ifdef EVENTS | ||
931 | INT int_EVENT_SELECT_FAILED | ||
932 | #endif | ||
933 | JUMP reject_message | ||
934 | |||
935 | munge_2: | ||
936 | JUMP reject_message | ||
937 | ; | ||
938 | ; The SCSI standard allows targets to recover from transient | ||
939 | ; error conditions by backing up the data pointer with a | ||
940 | ; RESTORE POINTERS message. | ||
941 | ; | ||
942 | ; So, we must save and restore the _residual_ code as well as | ||
943 | ; the current instruction pointer. Because of this messiness, | ||
944 | ; it is simpler to put dynamic code in the dsa for this and to | ||
945 | ; just do a simple jump down there. | ||
946 | ; | ||
947 | |||
948 | munge_save_data_pointer: | ||
949 | #if (CHIP == 710) | ||
950 | ; We have something in TEMP here, so first we must save that | ||
951 | MOVE TEMP0 TO SFBR | ||
952 | MOVE SFBR TO SCRATCH0 | ||
953 | MOVE TEMP1 TO SFBR | ||
954 | MOVE SFBR TO SCRATCH1 | ||
955 | MOVE TEMP2 TO SFBR | ||
956 | MOVE SFBR TO SCRATCH2 | ||
957 | MOVE TEMP3 TO SFBR | ||
958 | MOVE SFBR TO SCRATCH3 | ||
959 | MOVE MEMORY 4, addr_scratch, jump_temp + 4 | ||
960 | ; Now restore DSA | ||
961 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
962 | #endif | ||
963 | MOVE DSA0 + dsa_save_data_pointer TO SFBR | ||
964 | MOVE SFBR TO SCRATCH0 | ||
965 | MOVE DSA1 + 0xff TO SFBR WITH CARRY | ||
966 | MOVE SFBR TO SCRATCH1 | ||
967 | MOVE DSA2 + 0xff TO SFBR WITH CARRY | ||
968 | MOVE SFBR TO SCRATCH2 | ||
969 | MOVE DSA3 + 0xff TO SFBR WITH CARRY | ||
970 | MOVE SFBR TO SCRATCH3 | ||
971 | |||
972 | DMODE_NCR_TO_MEMORY | ||
973 | MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4 | ||
974 | DMODE_MEMORY_TO_MEMORY | ||
975 | jump_dsa_save: | ||
976 | JUMP 0 | ||
977 | |||
978 | munge_restore_pointers: | ||
979 | #if (CHIP == 710) | ||
980 | ; The code at dsa_restore_pointers will RETURN, but we don't care | ||
981 | ; about TEMP here, as it will overwrite it anyway. | ||
982 | #endif | ||
983 | MOVE DSA0 + dsa_restore_pointers TO SFBR | ||
984 | MOVE SFBR TO SCRATCH0 | ||
985 | MOVE DSA1 + 0xff TO SFBR WITH CARRY | ||
986 | MOVE SFBR TO SCRATCH1 | ||
987 | MOVE DSA2 + 0xff TO SFBR WITH CARRY | ||
988 | MOVE SFBR TO SCRATCH2 | ||
989 | MOVE DSA3 + 0xff TO SFBR WITH CARRY | ||
990 | MOVE SFBR TO SCRATCH3 | ||
991 | |||
992 | DMODE_NCR_TO_MEMORY | ||
993 | MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4 | ||
994 | DMODE_MEMORY_TO_MEMORY | ||
995 | jump_dsa_restore: | ||
996 | JUMP 0 | ||
997 | |||
998 | |||
999 | munge_disconnect: | ||
1000 | #ifdef DEBUG | ||
1001 | INT int_debug_disconnect_msg | ||
1002 | #endif | ||
1003 | |||
1004 | /* | ||
1005 | * Before, we overlapped processing with waiting for disconnect, but | ||
1006 | * debugging was beginning to appear messy. Temporarily move things | ||
1007 | * to just before the WAIT DISCONNECT. | ||
1008 | */ | ||
1009 | |||
1010 | #ifdef ORIGINAL | ||
1011 | #if (CHIP == 710) | ||
1012 | ; Following clears Unexpected Disconnect bit. What do we do? | ||
1013 | #else | ||
1014 | MOVE SCNTL2 & 0x7f TO SCNTL2 | ||
1015 | #endif | ||
1016 | CLEAR ACK | ||
1017 | #endif | ||
1018 | |||
1019 | #if (CHIP != 700) && (CHIP != 70066) | ||
1020 | JUMP dsa_schedule | ||
1021 | #else | ||
1022 | WAIT DISCONNECT | ||
1023 | INT int_norm_disconnected | ||
1024 | #endif | ||
1025 | |||
1026 | munge_extended: | ||
1027 | CLEAR ACK | ||
1028 | INT int_err_unexpected_phase, WHEN NOT MSG_IN | ||
1029 | MOVE 1, msg_buf + 1, WHEN MSG_IN | ||
1030 | JUMP munge_extended_2, IF 0x02 | ||
1031 | JUMP munge_extended_3, IF 0x03 | ||
1032 | JUMP reject_message | ||
1033 | |||
1034 | munge_extended_2: | ||
1035 | CLEAR ACK | ||
1036 | MOVE 1, msg_buf + 2, WHEN MSG_IN | ||
1037 | JUMP reject_message, IF NOT 0x02 ; Must be WDTR | ||
1038 | CLEAR ACK | ||
1039 | MOVE 1, msg_buf + 3, WHEN MSG_IN | ||
1040 | INT int_msg_wdtr | ||
1041 | |||
1042 | munge_extended_3: | ||
1043 | CLEAR ACK | ||
1044 | MOVE 1, msg_buf + 2, WHEN MSG_IN | ||
1045 | JUMP reject_message, IF NOT 0x01 ; Must be SDTR | ||
1046 | CLEAR ACK | ||
1047 | MOVE 2, msg_buf + 3, WHEN MSG_IN | ||
1048 | INT int_msg_sdtr | ||
1049 | |||
1050 | ENTRY reject_message | ||
1051 | reject_message: | ||
1052 | SET ATN | ||
1053 | CLEAR ACK | ||
1054 | MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT | ||
1055 | RETURN | ||
1056 | |||
1057 | ENTRY accept_message | ||
1058 | accept_message: | ||
1059 | CLEAR ATN | ||
1060 | CLEAR ACK | ||
1061 | RETURN | ||
1062 | |||
1063 | ENTRY respond_message | ||
1064 | respond_message: | ||
1065 | SET ATN | ||
1066 | CLEAR ACK | ||
1067 | MOVE FROM dsa_msgout_other, WHEN MSG_OUT | ||
1068 | RETURN | ||
1069 | |||
1070 | ; | ||
1071 | ; command_complete | ||
1072 | ; | ||
1073 | ; PURPOSE : handle command termination when STATUS IN is detected by reading | ||
1074 | ; a status byte followed by a command termination message. | ||
1075 | ; | ||
1076 | ; Normal termination results in an INTFLY instruction, and | ||
1077 | ; the host system can pick out which command terminated by | ||
1078 | ; examining the MESSAGE and STATUS buffers of all currently | ||
1079 | ; executing commands; | ||
1080 | ; | ||
1081 | ; Abnormal (CHECK_CONDITION) termination results in an | ||
1082 | ; int_err_check_condition interrupt so that a REQUEST SENSE | ||
1083 | ; command can be issued out-of-order so that no other command | ||
1084 | ; clears the contingent allegiance condition. | ||
1085 | ; | ||
1086 | ; | ||
1087 | ; INPUTS : DSA - command | ||
1088 | ; | ||
1089 | ; CALLS : OK | ||
1090 | ; | ||
1091 | ; EXITS : On successful termination, control is passed to schedule. | ||
1092 | ; On abnormal termination, the user will usually modify the | ||
1093 | ; DSA fields and corresponding buffers and return control | ||
1094 | ; to select. | ||
1095 | ; | ||
1096 | |||
1097 | ENTRY command_complete | ||
1098 | command_complete: | ||
1099 | MOVE FROM dsa_status, WHEN STATUS | ||
1100 | #if (CHIP != 700) && (CHIP != 70066) | ||
1101 | MOVE SFBR TO SCRATCH0 ; Save status | ||
1102 | #endif /* (CHIP != 700) && (CHIP != 70066) */ | ||
1103 | ENTRY command_complete_msgin | ||
1104 | command_complete_msgin: | ||
1105 | MOVE FROM dsa_msgin, WHEN MSG_IN | ||
1106 | ; Indicate that we should be expecting a disconnect | ||
1107 | #if (CHIP != 710) | ||
1108 | MOVE SCNTL2 & 0x7f TO SCNTL2 | ||
1109 | #else | ||
1110 | ; Above code cleared the Unexpected Disconnect bit, what do we do? | ||
1111 | #endif | ||
1112 | CLEAR ACK | ||
1113 | #if (CHIP != 700) && (CHIP != 70066) | ||
1114 | WAIT DISCONNECT | ||
1115 | |||
1116 | ; | ||
1117 | ; The SCSI specification states that when a UNIT ATTENTION condition | ||
1118 | ; is pending, as indicated by a CHECK CONDITION status message, | ||
1119 | ; the target shall revert to asynchronous transfers. Since | ||
1120 | ; synchronous transfers parameters are maintained on a per INITIATOR/TARGET | ||
1121 | ; basis, and returning control to our scheduler could work on a command | ||
1122 | ; running on another lun on that target using the old parameters, we must | ||
1123 | ; interrupt the host processor to get them changed, or change them ourselves. | ||
1124 | ; | ||
1125 | ; Once SCSI-II tagged queueing is implemented, things will be even more | ||
1126 | ; hairy, since contingent allegiance conditions exist on a per-target/lun | ||
1127 | ; basis, and issuing a new command with a different tag would clear it. | ||
1128 | ; In these cases, we must interrupt the host processor to get a request | ||
1129 | ; added to the HEAD of the queue with the request sense command, or we | ||
1130 | ; must automatically issue the request sense command. | ||
1131 | |||
1132 | #if 0 | ||
1133 | MOVE SCRATCH0 TO SFBR | ||
1134 | JUMP command_failed, IF 0x02 | ||
1135 | #endif | ||
1136 | #if (CHIP == 710) | ||
1137 | #if defined(MVME16x_INTFLY) | ||
1138 | ; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software | ||
1139 | ; interrupt (SW7). We can use SCRATCH, as we are about to jump to | ||
1140 | ; schedule, which corrupts it anyway. Will probably remove this later, | ||
1141 | ; but want to check performance effects first. | ||
1142 | |||
1143 | #define INTFLY_ADDR 0xfff40070 | ||
1144 | |||
1145 | MOVE 0 TO SCRATCH0 | ||
1146 | MOVE 0x80 TO SCRATCH1 | ||
1147 | MOVE 0 TO SCRATCH2 | ||
1148 | MOVE 0 TO SCRATCH3 | ||
1149 | MOVE MEMORY 4, addr_scratch, INTFLY_ADDR | ||
1150 | #else | ||
1151 | INT int_norm_emulateintfly | ||
1152 | #endif | ||
1153 | #else | ||
1154 | INTFLY | ||
1155 | #endif | ||
1156 | #endif /* (CHIP != 700) && (CHIP != 70066) */ | ||
1157 | #if (CHIP == 710) | ||
1158 | ; Time to correct DSA following memory move | ||
1159 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
1160 | #endif | ||
1161 | #ifdef EVENTS | ||
1162 | INT int_EVENT_COMPLETE | ||
1163 | #endif | ||
1164 | #if (CHIP != 700) && (CHIP != 70066) | ||
1165 | JUMP schedule | ||
1166 | command_failed: | ||
1167 | INT int_err_check_condition | ||
1168 | #else | ||
1169 | INT int_norm_command_complete | ||
1170 | #endif | ||
1171 | |||
1172 | ; | ||
1173 | ; wait_reselect | ||
1174 | ; | ||
1175 | ; PURPOSE : This is essentially the idle routine, where control lands | ||
1176 | ; when there are no new processes to schedule. wait_reselect | ||
1177 | ; waits for reselection, selection, and new commands. | ||
1178 | ; | ||
1179 | ; When a successful reselection occurs, with the aid | ||
1180 | ; of fixed up code in each DSA, wait_reselect walks the | ||
1181 | ; reconnect_dsa_queue, asking each dsa if the target ID | ||
1182 | ; and LUN match its. | ||
1183 | ; | ||
1184 | ; If a match is found, a call is made back to reselected_ok, | ||
1185 | ; which through the miracles of self modifying code, extracts | ||
1186 | ; the found DSA from the reconnect_dsa_queue and then | ||
1187 | ; returns control to the DSAs thread of execution. | ||
1188 | ; | ||
1189 | ; INPUTS : NONE | ||
1190 | ; | ||
1191 | ; CALLS : OK | ||
1192 | ; | ||
1193 | ; MODIFIES : DSA, | ||
1194 | ; | ||
1195 | ; EXITS : On successful reselection, control is returned to the | ||
1196 | ; DSA which called reselected_ok. If the WAIT RESELECT | ||
1197 | ; was interrupted by a new commands arrival signaled by | ||
1198 | ; SIG_P, control is passed to schedule. If the NCR is | ||
1199 | ; selected, the host system is interrupted with an | ||
1200 | ; int_err_selected which is usually responded to by | ||
1201 | ; setting DSP to the target_abort address. | ||
1202 | |||
1203 | ENTRY wait_reselect | ||
1204 | wait_reselect: | ||
1205 | #ifdef EVENTS | ||
1206 | int int_EVENT_IDLE | ||
1207 | #endif | ||
1208 | #ifdef DEBUG | ||
1209 | int int_debug_idle | ||
1210 | #endif | ||
1211 | WAIT RESELECT wait_reselect_failed | ||
1212 | |||
1213 | reselected: | ||
1214 | #ifdef EVENTS | ||
1215 | int int_EVENT_RESELECT | ||
1216 | #endif | ||
1217 | CLEAR TARGET | ||
1218 | DMODE_MEMORY_TO_MEMORY | ||
1219 | ; Read all data needed to reestablish the nexus - | ||
1220 | MOVE 1, reselected_identify, WHEN MSG_IN | ||
1221 | ; We used to CLEAR ACK here. | ||
1222 | #if (CHIP != 700) && (CHIP != 70066) | ||
1223 | #ifdef DEBUG | ||
1224 | int int_debug_reselected | ||
1225 | #endif | ||
1226 | |||
1227 | ; Point DSA at the current head of the disconnected queue. | ||
1228 | DMODE_MEMORY_TO_NCR | ||
1229 | MOVE MEMORY 4, reconnect_dsa_head, addr_scratch | ||
1230 | DMODE_MEMORY_TO_MEMORY | ||
1231 | #if (CHIP == 710) | ||
1232 | MOVE MEMORY 4, addr_scratch, saved_dsa | ||
1233 | #else | ||
1234 | CALL scratch_to_dsa | ||
1235 | #endif | ||
1236 | |||
1237 | ; Fix the update-next pointer so that the reconnect_dsa_head | ||
1238 | ; pointer is the one that will be updated if this DSA is a hit | ||
1239 | ; and we remove it from the queue. | ||
1240 | |||
1241 | MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8 | ||
1242 | #if (CHIP == 710) | ||
1243 | ; Time to correct DSA following memory move | ||
1244 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
1245 | #endif | ||
1246 | |||
1247 | ENTRY reselected_check_next | ||
1248 | reselected_check_next: | ||
1249 | #ifdef DEBUG | ||
1250 | INT int_debug_reselect_check | ||
1251 | #endif | ||
1252 | ; Check for a NULL pointer. | ||
1253 | MOVE DSA0 TO SFBR | ||
1254 | JUMP reselected_not_end, IF NOT 0 | ||
1255 | MOVE DSA1 TO SFBR | ||
1256 | JUMP reselected_not_end, IF NOT 0 | ||
1257 | MOVE DSA2 TO SFBR | ||
1258 | JUMP reselected_not_end, IF NOT 0 | ||
1259 | MOVE DSA3 TO SFBR | ||
1260 | JUMP reselected_not_end, IF NOT 0 | ||
1261 | INT int_err_unexpected_reselect | ||
1262 | |||
1263 | reselected_not_end: | ||
1264 | ; | ||
1265 | ; XXX the ALU is only eight bits wide, and the assembler | ||
1266 | ; wont do the dirt work for us. As long as dsa_check_reselect | ||
1267 | ; is negative, we need to sign extend with 1 bits to the full | ||
1268 | ; 32 bit width of the address. | ||
1269 | ; | ||
1270 | ; A potential work around would be to have a known alignment | ||
1271 | ; of the DSA structure such that the base address plus | ||
1272 | ; dsa_check_reselect doesn't require carrying from bytes | ||
1273 | ; higher than the LSB. | ||
1274 | ; | ||
1275 | |||
1276 | MOVE DSA0 TO SFBR | ||
1277 | MOVE SFBR + dsa_check_reselect TO SCRATCH0 | ||
1278 | MOVE DSA1 TO SFBR | ||
1279 | MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY | ||
1280 | MOVE DSA2 TO SFBR | ||
1281 | MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY | ||
1282 | MOVE DSA3 TO SFBR | ||
1283 | MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY | ||
1284 | |||
1285 | DMODE_NCR_TO_MEMORY | ||
1286 | MOVE MEMORY 4, addr_scratch, reselected_check + 4 | ||
1287 | DMODE_MEMORY_TO_MEMORY | ||
1288 | #if (CHIP == 710) | ||
1289 | ; Time to correct DSA following memory move | ||
1290 | MOVE MEMORY 4, saved_dsa, addr_dsa | ||
1291 | #endif | ||
1292 | reselected_check: | ||
1293 | JUMP 0 | ||
1294 | |||
1295 | |||
1296 | ; | ||
1297 | ; | ||
1298 | #if (CHIP == 710) | ||
1299 | ; We have problems here - the memory move corrupts TEMP and DSA. This | ||
1300 | ; routine is called from DSA code, and patched from many places. Scratch | ||
1301 | ; is probably free when it is called. | ||
1302 | ; We have to: | ||
1303 | ; copy temp to scratch, one byte at a time | ||
1304 | ; write scratch to patch a jump in place of the return | ||
1305 | ; do the move memory | ||
1306 | ; jump to the patched in return address | ||
1307 | ; DSA is corrupt when we get here, and can be left corrupt | ||
1308 | |||
1309 | ENTRY reselected_ok | ||
1310 | reselected_ok: | ||
1311 | MOVE TEMP0 TO SFBR | ||
1312 | MOVE SFBR TO SCRATCH0 | ||
1313 | MOVE TEMP1 TO SFBR | ||
1314 | MOVE SFBR TO SCRATCH1 | ||
1315 | MOVE TEMP2 TO SFBR | ||
1316 | MOVE SFBR TO SCRATCH2 | ||
1317 | MOVE TEMP3 TO SFBR | ||
1318 | MOVE SFBR TO SCRATCH3 | ||
1319 | MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4 | ||
1320 | reselected_ok_patch: | ||
1321 | MOVE MEMORY 4, 0, 0 | ||
1322 | reselected_ok_jump: | ||
1323 | JUMP 0 | ||
1324 | #else | ||
1325 | ENTRY reselected_ok | ||
1326 | reselected_ok: | ||
1327 | reselected_ok_patch: | ||
1328 | MOVE MEMORY 4, 0, 0 ; Patched : first word | ||
1329 | ; is address of | ||
1330 | ; successful dsa_next | ||
1331 | ; Second word is last | ||
1332 | ; unsuccessful dsa_next, | ||
1333 | ; starting with | ||
1334 | ; dsa_reconnect_head | ||
1335 | ; We used to CLEAR ACK here. | ||
1336 | #ifdef DEBUG | ||
1337 | INT int_debug_reselected_ok | ||
1338 | #endif | ||
1339 | #ifdef DEBUG | ||
1340 | INT int_debug_check_dsa | ||
1341 | #endif | ||
1342 | RETURN ; Return control to where | ||
1343 | #endif | ||
1344 | #else | ||
1345 | INT int_norm_reselected | ||
1346 | #endif /* (CHIP != 700) && (CHIP != 70066) */ | ||
1347 | |||
1348 | selected: | ||
1349 | INT int_err_selected; | ||
1350 | |||
1351 | ; | ||
1352 | ; A select or reselect failure can be caused by one of two conditions : | ||
1353 | ; 1. SIG_P was set. This will be the case if the user has written | ||
1354 | ; a new value to a previously NULL head of the issue queue. | ||
1355 | ; | ||
1356 | ; 2. The NCR53c810 was selected or reselected by another device. | ||
1357 | ; | ||
1358 | ; 3. The bus was already busy since we were selected or reselected | ||
1359 | ; before starting the command. | ||
1360 | |||
1361 | wait_reselect_failed: | ||
1362 | #ifdef EVENTS | ||
1363 | INT int_EVENT_RESELECT_FAILED | ||
1364 | #endif | ||
1365 | ; Check selected bit. | ||
1366 | #if (CHIP == 710) | ||
1367 | ; Must work out how to tell if we are selected.... | ||
1368 | #else | ||
1369 | MOVE SIST0 & 0x20 TO SFBR | ||
1370 | JUMP selected, IF 0x20 | ||
1371 | #endif | ||
1372 | ; Reading CTEST2 clears the SIG_P bit in the ISTAT register. | ||
1373 | MOVE CTEST2 & 0x40 TO SFBR | ||
1374 | JUMP schedule, IF 0x40 | ||
1375 | ; Check connected bit. | ||
1376 | ; FIXME: this needs to change if we support target mode | ||
1377 | MOVE ISTAT & 0x08 TO SFBR | ||
1378 | JUMP reselected, IF 0x08 | ||
1379 | ; FIXME : Something bogus happened, and we shouldn't fail silently. | ||
1380 | #if 0 | ||
1381 | JUMP schedule | ||
1382 | #else | ||
1383 | INT int_debug_panic | ||
1384 | #endif | ||
1385 | |||
1386 | |||
1387 | select_failed: | ||
1388 | #if (CHIP == 710) | ||
1389 | ; Disable selection timer | ||
1390 | MOVE CTEST7 | 0x10 TO CTEST7 | ||
1391 | #endif | ||
1392 | #ifdef EVENTS | ||
1393 | int int_EVENT_SELECT_FAILED | ||
1394 | #endif | ||
1395 | ; Otherwise, mask the selected and reselected bits off SIST0 | ||
1396 | #if (CHIP ==710) | ||
1397 | ; Let's assume we don't get selected for now | ||
1398 | MOVE SSTAT0 & 0x10 TO SFBR | ||
1399 | #else | ||
1400 | MOVE SIST0 & 0x30 TO SFBR | ||
1401 | JUMP selected, IF 0x20 | ||
1402 | #endif | ||
1403 | JUMP reselected, IF 0x10 | ||
1404 | ; If SIGP is set, the user just gave us another command, and | ||
1405 | ; we should restart or return to the scheduler. | ||
1406 | ; Reading CTEST2 clears the SIG_P bit in the ISTAT register. | ||
1407 | MOVE CTEST2 & 0x40 TO SFBR | ||
1408 | JUMP select, IF 0x40 | ||
1409 | ; Check connected bit. | ||
1410 | ; FIXME: this needs to change if we support target mode | ||
1411 | ; FIXME: is this really necessary? | ||
1412 | MOVE ISTAT & 0x08 TO SFBR | ||
1413 | JUMP reselected, IF 0x08 | ||
1414 | ; FIXME : Something bogus happened, and we shouldn't fail silently. | ||
1415 | #if 0 | ||
1416 | JUMP schedule | ||
1417 | #else | ||
1418 | INT int_debug_panic | ||
1419 | #endif | ||
1420 | |||
1421 | ; | ||
1422 | ; test_1 | ||
1423 | ; test_2 | ||
1424 | ; | ||
1425 | ; PURPOSE : run some verification tests on the NCR. test_1 | ||
1426 | ; copies test_src to test_dest and interrupts the host | ||
1427 | ; processor, testing for cache coherency and interrupt | ||
1428 | ; problems in the processes. | ||
1429 | ; | ||
1430 | ; test_2 runs a command with offsets relative to the | ||
1431 | ; DSA on entry, and is useful for miscellaneous experimentation. | ||
1432 | ; | ||
1433 | |||
1434 | ; Verify that interrupts are working correctly and that we don't | ||
1435 | ; have a cache invalidation problem. | ||
1436 | |||
1437 | ABSOLUTE test_src = 0, test_dest = 0 | ||
1438 | ENTRY test_1 | ||
1439 | test_1: | ||
1440 | MOVE MEMORY 4, test_src, test_dest | ||
1441 | INT int_test_1 | ||
1442 | |||
1443 | ; | ||
1444 | ; Run arbitrary commands, with test code establishing a DSA | ||
1445 | ; | ||
1446 | |||
1447 | ENTRY test_2 | ||
1448 | test_2: | ||
1449 | CLEAR TARGET | ||
1450 | #if (CHIP == 710) | ||
1451 | ; Enable selection timer | ||
1452 | #ifdef NO_SELECTION_TIMEOUT | ||
1453 | MOVE CTEST7 & 0xff TO CTEST7 | ||
1454 | #else | ||
1455 | MOVE CTEST7 & 0xef TO CTEST7 | ||
1456 | #endif | ||
1457 | #endif | ||
1458 | SELECT ATN FROM 0, test_2_fail | ||
1459 | JUMP test_2_msgout, WHEN MSG_OUT | ||
1460 | ENTRY test_2_msgout | ||
1461 | test_2_msgout: | ||
1462 | #if (CHIP == 710) | ||
1463 | ; Disable selection timer | ||
1464 | MOVE CTEST7 | 0x10 TO CTEST7 | ||
1465 | #endif | ||
1466 | MOVE FROM 8, WHEN MSG_OUT | ||
1467 | MOVE FROM 16, WHEN CMD | ||
1468 | MOVE FROM 24, WHEN DATA_IN | ||
1469 | MOVE FROM 32, WHEN STATUS | ||
1470 | MOVE FROM 40, WHEN MSG_IN | ||
1471 | #if (CHIP != 710) | ||
1472 | MOVE SCNTL2 & 0x7f TO SCNTL2 | ||
1473 | #endif | ||
1474 | CLEAR ACK | ||
1475 | WAIT DISCONNECT | ||
1476 | test_2_fail: | ||
1477 | #if (CHIP == 710) | ||
1478 | ; Disable selection timer | ||
1479 | MOVE CTEST7 | 0x10 TO CTEST7 | ||
1480 | #endif | ||
1481 | INT int_test_2 | ||
1482 | |||
1483 | ENTRY debug_break | ||
1484 | debug_break: | ||
1485 | INT int_debug_break | ||
1486 | |||
1487 | ; | ||
1488 | ; initiator_abort | ||
1489 | ; target_abort | ||
1490 | ; | ||
1491 | ; PURPOSE : Abort the currently established nexus from with initiator | ||
1492 | ; or target mode. | ||
1493 | ; | ||
1494 | ; | ||
1495 | |||
1496 | ENTRY target_abort | ||
1497 | target_abort: | ||
1498 | SET TARGET | ||
1499 | DISCONNECT | ||
1500 | CLEAR TARGET | ||
1501 | JUMP schedule | ||
1502 | |||
1503 | ENTRY initiator_abort | ||
1504 | initiator_abort: | ||
1505 | SET ATN | ||
1506 | ; | ||
1507 | ; The SCSI-I specification says that targets may go into MSG out at | ||
1508 | ; their leisure upon receipt of the ATN single. On all versions of the | ||
1509 | ; specification, we can't change phases until REQ transitions true->false, | ||
1510 | ; so we need to sink/source one byte of data to allow the transition. | ||
1511 | ; | ||
1512 | ; For the sake of safety, we'll only source one byte of data in all | ||
1513 | ; cases, but to accommodate the SCSI-I dain bramage, we'll sink an | ||
1514 | ; arbitrary number of bytes. | ||
1515 | JUMP spew_cmd, WHEN CMD | ||
1516 | JUMP eat_msgin, WHEN MSG_IN | ||
1517 | JUMP eat_datain, WHEN DATA_IN | ||
1518 | JUMP eat_status, WHEN STATUS | ||
1519 | JUMP spew_dataout, WHEN DATA_OUT | ||
1520 | JUMP sated | ||
1521 | spew_cmd: | ||
1522 | MOVE 1, NCR53c7xx_zero, WHEN CMD | ||
1523 | JUMP sated | ||
1524 | eat_msgin: | ||
1525 | MOVE 1, NCR53c7xx_sink, WHEN MSG_IN | ||
1526 | JUMP eat_msgin, WHEN MSG_IN | ||
1527 | JUMP sated | ||
1528 | eat_status: | ||
1529 | MOVE 1, NCR53c7xx_sink, WHEN STATUS | ||
1530 | JUMP eat_status, WHEN STATUS | ||
1531 | JUMP sated | ||
1532 | eat_datain: | ||
1533 | MOVE 1, NCR53c7xx_sink, WHEN DATA_IN | ||
1534 | JUMP eat_datain, WHEN DATA_IN | ||
1535 | JUMP sated | ||
1536 | spew_dataout: | ||
1537 | MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT | ||
1538 | sated: | ||
1539 | #if (CHIP != 710) | ||
1540 | MOVE SCNTL2 & 0x7f TO SCNTL2 | ||
1541 | #endif | ||
1542 | MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT | ||
1543 | WAIT DISCONNECT | ||
1544 | INT int_norm_aborted | ||
1545 | |||
1546 | #if (CHIP != 710) | ||
1547 | ; | ||
1548 | ; dsa_to_scratch | ||
1549 | ; scratch_to_dsa | ||
1550 | ; | ||
1551 | ; PURPOSE : | ||
1552 | ; The NCR chips cannot do a move memory instruction with the DSA register | ||
1553 | ; as the source or destination. So, we provide a couple of subroutines | ||
1554 | ; that let us switch between the DSA register and scratch register. | ||
1555 | ; | ||
1556 | ; Memory moves to/from the DSPS register also don't work, but we | ||
1557 | ; don't use them. | ||
1558 | ; | ||
1559 | ; | ||
1560 | |||
1561 | |||
1562 | dsa_to_scratch: | ||
1563 | MOVE DSA0 TO SFBR | ||
1564 | MOVE SFBR TO SCRATCH0 | ||
1565 | MOVE DSA1 TO SFBR | ||
1566 | MOVE SFBR TO SCRATCH1 | ||
1567 | MOVE DSA2 TO SFBR | ||
1568 | MOVE SFBR TO SCRATCH2 | ||
1569 | MOVE DSA3 TO SFBR | ||
1570 | MOVE SFBR TO SCRATCH3 | ||
1571 | RETURN | ||
1572 | |||
1573 | scratch_to_dsa: | ||
1574 | MOVE SCRATCH0 TO SFBR | ||
1575 | MOVE SFBR TO DSA0 | ||
1576 | MOVE SCRATCH1 TO SFBR | ||
1577 | MOVE SFBR TO DSA1 | ||
1578 | MOVE SCRATCH2 TO SFBR | ||
1579 | MOVE SFBR TO DSA2 | ||
1580 | MOVE SCRATCH3 TO SFBR | ||
1581 | MOVE SFBR TO DSA3 | ||
1582 | RETURN | ||
1583 | #endif | ||
1584 | |||
1585 | #if (CHIP == 710) | ||
1586 | ; Little patched jump, used to overcome problems with TEMP getting | ||
1587 | ; corrupted on memory moves. | ||
1588 | |||
1589 | jump_temp: | ||
1590 | JUMP 0 | ||
1591 | #endif | ||