]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 [[email protected]] | |
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 | ; [email protected] | |
16 | ; | |
17 | ; Copyright 1993, 1994, 1995 Drew Eckhardt | |
18 | ; Visionary Computing | |
19 | ; (Unix and Linux consulting and custom programming) | |
20 | ; [email protected] | |
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? [email protected] | |
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 |