- Kai Germaschewski: ISDN update (including Makefiles)
[davej-history.git] / drivers / scsi / 53c7,8xx.scr
blob76ee946747c7a34eed51229790f64284d467c707
1 #undef DEBUG
2 #undef EVENTS
3 ; NCR 53c810 driver, main script
4 ; Sponsored by 
5 ;       iX Multiuser Multitasking Magazine
6 ;       hm@ix.de
8 ; Copyright 1993, 1994, 1995 Drew Eckhardt
9 ;      Visionary Computing 
10 ;      (Unix and Linux consulting and custom programming)
11 ;      drew@PoohSticks.ORG
12 ;      +1 (303) 786-7975
14 ; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
16 ; PRE-ALPHA
18 ; For more information, please consult 
20 ; NCR 53C810
21 ; PCI-SCSI I/O Processor
22 ; Data Manual
24 ; NCR 53C710 
25 ; SCSI I/O Processor
26 ; Programmers Guide
28 ; NCR Microelectronics
29 ; 1635 Aeroplaza Drive
30 ; Colorado Springs, CO 80916
31 ; 1+ (719) 578-3400
33 ; Toll free literature number
34 ; +1 (800) 334-5454
36 ; IMPORTANT : This code is self modifying due to the limitations of 
37 ;       the NCR53c7,8xx series chips.  Persons debugging this code with
38 ;       the remote debugger should take this into account, and NOT set
39 ;       breakpoints in modified instructions.
41 ; Design:
42 ; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 
43 ; microcontroller using a simple instruction set.   
45 ; So, to minimize the effects of interrupt latency, and to maximize 
46 ; throughput, this driver offloads the practical maximum amount 
47 ; of processing to the SCSI chip while still maintaining a common
48 ; structure.
50 ; Where tradeoffs were needed between efficiency on the older
51 ; chips and the newer NCR53c800 series, the NCR53c800 series 
52 ; was chosen.
54 ; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
55 ; automate SCSI transfers without host processor intervention, this 
56 ; isn't the case with the NCR53c710 and newer chips which allow 
58 ; - reads and writes to the internal registers from within the SCSI
59 ;       scripts, allowing the SCSI SCRIPTS(tm) code to save processor
60 ;       state so that multiple threads of execution are possible, and also
61 ;       provide an ALU for loop control, etc.
62
63 ; - table indirect addressing for some instructions. This allows 
64 ;       pointers to be located relative to the DSA ((Data Structure
65 ;       Address) register.
67 ; These features make it possible to implement a mailbox style interface,
68 ; where the same piece of code is run to handle I/O for multiple threads
69 ; at once minimizing our need to relocate code.  Since the NCR53c700/
70 ; NCR53c800 series have a unique combination of features, making a 
71 ; a standard ingoing/outgoing mailbox system, costly, I've modified it.
73 ; - Mailboxes are a mixture of code and data.  This lets us greatly
74 ;       simplify the NCR53c810 code and do things that would otherwise
75 ;       not be possible.
77 ; The saved data pointer is now implemented as follows :
79 ;       Control flow has been architected such that if control reaches
80 ;       munge_save_data_pointer, on a restore pointers message or 
81 ;       reconnection, a jump to the address formerly in the TEMP register
82 ;       will allow the SCSI command to resume execution.
86 ; Note : the DSA structures must be aligned on 32 bit boundaries,
87 ; since the source and destination of MOVE MEMORY instructions 
88 ; must share the same alignment and this is the alignment of the
89 ; NCR registers.
92 ABSOLUTE dsa_temp_lun = 0               ; Patch to lun for current dsa
93 ABSOLUTE dsa_temp_next = 0              ; Patch to dsa next for current dsa
94 ABSOLUTE dsa_temp_addr_next = 0         ; Patch to address of dsa next address 
95                                         ;       for current dsa
96 ABSOLUTE dsa_temp_sync = 0              ; Patch to address of per-target
97                                         ;       sync routine
98 ABSOLUTE dsa_temp_target = 0            ; Patch to id for current dsa
99 ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
100                                         ;       saved data pointer
101 ABSOLUTE dsa_temp_addr_residual = 0     ; Patch to address of per-command
102                                         ;       current residual code
103 ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
104                                         ; saved residual code
105 ABSOLUTE dsa_temp_addr_new_value = 0    ; Address of value for JUMP operand
106 ABSOLUTE dsa_temp_addr_array_value = 0  ; Address to copy to
107 ABSOLUTE dsa_temp_addr_dsa_value = 0    ; Address of this DSA value
110 ; Once a device has initiated reselection, we need to compare it 
111 ; against the singly linked list of commands which have disconnected
112 ; and are pending reselection.  These commands are maintained in 
113 ; an unordered singly linked list of DSA structures, through the
114 ; DSA pointers at their 'centers' headed by the reconnect_dsa_head
115 ; pointer.
117 ; To avoid complications in removing commands from the list,
118 ; I minimize the amount of expensive (at eight operations per
119 ; addition @ 500-600ns each) pointer operations which must
120 ; be done in the NCR driver by precomputing them on the 
121 ; host processor during dsa structure generation.
123 ; The fixed-up per DSA code knows how to recognize the nexus
124 ; associated with the corresponding SCSI command, and modifies
125 ; the source and destination pointers for the MOVE MEMORY 
126 ; instruction which is executed when reselected_ok is called
127 ; to remove the command from the list.  Similarly, DSA is 
128 ; loaded with the address of the next DSA structure and
129 ; reselected_check_next is called if a failure occurs.
131 ; Perhaps more concisely, the net effect of the mess is 
133 ; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, 
134 ;     src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
135 ;       src = &dsa->next;
136 ;       if (target_id == dsa->id && target_lun == dsa->lun) {
137 ;               *dest = *src;
138 ;               break;
139 ;         }     
140 ; }
142 ; if (!dsa)
143 ;           error (int_err_unexpected_reselect);
144 ; else  
145 ;     longjmp (dsa->jump_resume, 0);
147 ;       
149 #if (CHIP != 700) && (CHIP != 70066)
150 ; Define DSA structure used for mailboxes
151 ENTRY dsa_code_template
152 dsa_code_template:
153 ENTRY dsa_code_begin
154 dsa_code_begin:
155         MOVE dmode_memory_to_ncr TO DMODE
156         MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
157         MOVE dmode_memory_to_memory TO DMODE
158         CALL scratch_to_dsa
159         CALL select
160 ; Handle the phase mismatch which may have resulted from the 
161 ; MOVE FROM dsa_msgout if we returned here.  The CLEAR ATN 
162 ; may or may not be necessary, and we should update script_asm.pl
163 ; to handle multiple pieces.
164     CLEAR ATN
165     CLEAR ACK
167 ; Replace second operand with address of JUMP instruction dest operand
168 ; in schedule table for this DSA.  Becomes dsa_jump_dest in 53c7,8xx.c.
169 ENTRY dsa_code_fix_jump
170 dsa_code_fix_jump:
171         MOVE MEMORY 4, NOP_insn, 0
172         JUMP select_done
174 ; wrong_dsa loads the DSA register with the value of the dsa_next
175 ; field.
177 wrong_dsa:
178 ;               Patch the MOVE MEMORY INSTRUCTION such that 
179 ;               the destination address is the address of the OLD 
180 ;               next pointer.
182         MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok + 8
183         MOVE dmode_memory_to_ncr TO DMODE       
185 ;       Move the _contents_ of the next pointer into the DSA register as 
186 ;       the next I_T_L or I_T_L_Q tupple to check against the established
187 ;       nexus.
189         MOVE MEMORY 4, dsa_temp_next, addr_scratch
190         MOVE dmode_memory_to_memory TO DMODE
191         CALL scratch_to_dsa
192         JUMP reselected_check_next
194 ABSOLUTE dsa_save_data_pointer = 0
195 ENTRY dsa_code_save_data_pointer
196 dsa_code_save_data_pointer:
197         MOVE dmode_ncr_to_memory TO DMODE
198         MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
199         MOVE dmode_memory_to_memory TO DMODE
200 ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
201         MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
202         CLEAR ACK
203 #ifdef DEBUG
204         INT int_debug_saved
205 #endif
206         RETURN
207 ABSOLUTE dsa_restore_pointers = 0
208 ENTRY dsa_code_restore_pointers
209 dsa_code_restore_pointers:
210         MOVE dmode_memory_to_ncr TO DMODE
211         MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
212         MOVE dmode_memory_to_memory TO DMODE
213 ; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
214         MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
215         CLEAR ACK
216 #ifdef DEBUG
217         INT int_debug_restored
218 #endif
219         RETURN
221 ABSOLUTE dsa_check_reselect = 0
222 ; dsa_check_reselect determines whether or not the current target and
223 ; lun match the current DSA
224 ENTRY dsa_code_check_reselect
225 dsa_code_check_reselect:
226         MOVE SSID TO SFBR               ; SSID contains 3 bit target ID
227 ; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
228         JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
230 ; Hack - move to scratch first, since SFBR is not writeable
231 ;       via the CPU and hence a MOVE MEMORY instruction.
233         MOVE dmode_memory_to_ncr TO DMODE
234         MOVE MEMORY 1, reselected_identify, addr_scratch
235         MOVE dmode_memory_to_memory TO DMODE
236         MOVE SCRATCH0 TO SFBR
237 ; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
238         JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
239 ;               Patch the MOVE MEMORY INSTRUCTION such that
240 ;               the source address is the address of this dsa's
241 ;               next pointer.
242         MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok + 4
243         CALL reselected_ok
244         CALL dsa_temp_sync      
245 ; Release ACK on the IDENTIFY message _after_ we've set the synchronous 
246 ; transfer parameters! 
247         CLEAR ACK
248 ; Implicitly restore pointers on reselection, so a RETURN
249 ; will transfer control back to the right spot.
250         CALL REL (dsa_code_restore_pointers)
251         RETURN
252 ENTRY dsa_zero
253 dsa_zero:
254 ENTRY dsa_code_template_end
255 dsa_code_template_end:
257 ; Perform sanity check for dsa_fields_start == dsa_code_template_end - 
258 ; dsa_zero, puke.
260 ABSOLUTE dsa_fields_start =  0  ; Sanity marker
261                                 ;       pad 48 bytes (fix this RSN)
262 ABSOLUTE dsa_next = 48          ; len 4 Next DSA
263                                 ; del 4 Previous DSA address
264 ABSOLUTE dsa_cmnd = 56          ; len 4 Scsi_Cmnd * for this thread.
265 ABSOLUTE dsa_select = 60        ; len 4 Device ID, Period, Offset for 
266                                 ;       table indirect select
267 ABSOLUTE dsa_msgout = 64        ; len 8 table indirect move parameter for 
268                                 ;       select message
269 ABSOLUTE dsa_cmdout = 72        ; len 8 table indirect move parameter for 
270                                 ;       command
271 ABSOLUTE dsa_dataout = 80       ; len 4 code pointer for dataout
272 ABSOLUTE dsa_datain = 84        ; len 4 code pointer for datain
273 ABSOLUTE dsa_msgin = 88         ; len 8 table indirect move for msgin
274 ABSOLUTE dsa_status = 96        ; len 8 table indirect move for status byte
275 ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
276                                 ; (Synchronous transfer negotiation, etc).
277 ABSOLUTE dsa_end = 112
279 ABSOLUTE schedule = 0           ; Array of JUMP dsa_begin or JUMP (next),
280                                 ; terminated by a call to JUMP wait_reselect
282 ; Linked lists of DSA structures
283 ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
284 ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
285                                 ; address of reconnect_dsa_head
287 ; These select the source and destination of a MOVE MEMORY instruction
288 ABSOLUTE dmode_memory_to_memory = 0x0
289 ABSOLUTE dmode_memory_to_ncr = 0x0
290 ABSOLUTE dmode_ncr_to_memory = 0x0
292 ABSOLUTE addr_scratch = 0x0
293 ABSOLUTE addr_temp = 0x0
294 #endif /* CHIP != 700 && CHIP != 70066 */
296 ; Interrupts - 
297 ; MSB indicates type
298 ; 0     handle error condition
299 ; 1     handle message 
300 ; 2     handle normal condition
301 ; 3     debugging interrupt
302 ; 4     testing interrupt 
303 ; Next byte indicates specific error
305 ; XXX not yet implemented, I'm not sure if I want to - 
306 ; Next byte indicates the routine the error occurred in
307 ; The LSB indicates the specific place the error occurred
309 ABSOLUTE int_err_unexpected_phase = 0x00000000  ; Unexpected phase encountered
310 ABSOLUTE int_err_selected = 0x00010000          ; SELECTED (nee RESELECTED)
311 ABSOLUTE int_err_unexpected_reselect = 0x00020000 
312 ABSOLUTE int_err_check_condition = 0x00030000   
313 ABSOLUTE int_err_no_phase = 0x00040000
314 ABSOLUTE int_msg_wdtr = 0x01000000              ; WDTR message received
315 ABSOLUTE int_msg_sdtr = 0x01010000              ; SDTR received
316 ABSOLUTE int_msg_1 = 0x01020000                 ; single byte special message
317                                                 ; received
319 ABSOLUTE int_norm_select_complete = 0x02000000  ; Select complete, reprogram
320                                                 ; registers.
321 ABSOLUTE int_norm_reselect_complete = 0x02010000        ; Nexus established
322 ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
323 ABSOLUTE int_norm_disconnected = 0x02030000     ; Disconnected 
324 ABSOLUTE int_norm_aborted =0x02040000           ; Aborted *dsa
325 ABSOLUTE int_norm_reset = 0x02050000            ; Generated BUS reset.
326 ABSOLUTE int_debug_break = 0x03000000           ; Break point
327 #ifdef DEBUG
328 ABSOLUTE int_debug_scheduled = 0x03010000       ; new I/O scheduled 
329 ABSOLUTE int_debug_idle = 0x03020000            ; scheduler is idle
330 ABSOLUTE int_debug_dsa_loaded = 0x03030000      ; dsa reloaded
331 ABSOLUTE int_debug_reselected = 0x03040000      ; NCR reselected
332 ABSOLUTE int_debug_head = 0x03050000            ; issue head overwritten
333 ABSOLUTE int_debug_disconnected = 0x03060000    ; disconnected
334 ABSOLUTE int_debug_disconnect_msg = 0x03070000  ; got message to disconnect
335 ABSOLUTE int_debug_dsa_schedule = 0x03080000    ; in dsa_schedule
336 ABSOLUTE int_debug_reselect_check = 0x03090000  ; Check for reselection of DSA
337 ABSOLUTE int_debug_reselected_ok = 0x030a0000   ; Reselection accepted
338 #endif
339 ABSOLUTE int_debug_panic = 0x030b0000           ; Panic driver
340 #ifdef DEBUG
341 ABSOLUTE int_debug_saved = 0x030c0000           ; save/restore pointers
342 ABSOLUTE int_debug_restored = 0x030d0000
343 ABSOLUTE int_debug_sync = 0x030e0000            ; Sanity check synchronous 
344                                                 ; parameters. 
345 ABSOLUTE int_debug_datain = 0x030f0000          ; going into data in phase 
346                                                 ; now.
347 ABSOLUTE int_debug_check_dsa = 0x03100000       ; Sanity check DSA against
348                                                 ; SDID.
349 #endif
351 ABSOLUTE int_test_1 = 0x04000000                ; Test 1 complete
352 ABSOLUTE int_test_2 = 0x04010000                ; Test 2 complete
353 ABSOLUTE int_test_3 = 0x04020000                ; Test 3 complete
356 ; These should start with 0x05000000, with low bits incrementing for 
357 ; each one.
359 #ifdef EVENTS
360 ABSOLUTE int_EVENT_SELECT = 0
361 ABSOLUTE int_EVENT_DISCONNECT = 0
362 ABSOLUTE int_EVENT_RESELECT = 0
363 ABSOLUTE int_EVENT_COMPLETE = 0
364 ABSOLUTE int_EVENT_IDLE = 0
365 ABSOLUTE int_EVENT_SELECT_FAILED = 0
366 ABSOLUTE int_EVENT_BEFORE_SELECT = 0
367 ABSOLUTE int_EVENT_RESELECT_FAILED = 0
368 #endif
369                                                 
370 ABSOLUTE NCR53c7xx_msg_abort = 0        ; Pointer to abort message
371 ABSOLUTE NCR53c7xx_msg_reject = 0       ; Pointer to reject message
372 ABSOLUTE NCR53c7xx_zero = 0             ; long with zero in it, use for source
373 ABSOLUTE NCR53c7xx_sink = 0             ; long to dump worthless data in
374 ABSOLUTE NOP_insn = 0                   ; NOP instruction
376 ; Pointer to message, potentially multi-byte
377 ABSOLUTE msg_buf = 0
379 ; Pointer to holding area for reselection information
380 ABSOLUTE reselected_identify = 0
381 ABSOLUTE reselected_tag = 0
383 ; Request sense command pointer, it's a 6 byte command, should
384 ; be constant for all commands since we always want 16 bytes of 
385 ; sense and we don't need to change any fields as we did under 
386 ; SCSI-I when we actually cared about the LUN field.
387 ;EXTERNAL NCR53c7xx_sense               ; Request sense command
389 #if (CHIP != 700) && (CHIP != 70066)
390 ; dsa_schedule  
391 ; PURPOSE : after a DISCONNECT message has been received, and pointers
392 ;       saved, insert the current DSA structure at the head of the 
393 ;       disconnected queue and fall through to the scheduler.
395 ; CALLS : OK
397 ; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
398 ;       of disconnected commands
400 ; MODIFIES : SCRATCH, reconnect_dsa_head
402 ; EXITS : always passes control to schedule
404 ENTRY dsa_schedule
405 dsa_schedule:
406 #if 0
407     INT int_debug_dsa_schedule
408 #endif
411 ; Calculate the address of the next pointer within the DSA 
412 ; structure of the command that is currently disconnecting
414     CALL dsa_to_scratch
415     MOVE SCRATCH0 + dsa_next TO SCRATCH0
416     MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
417     MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
418     MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
420 ; Point the next field of this DSA structure at the current disconnected 
421 ; list
422     MOVE dmode_ncr_to_memory TO DMODE
423     MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
424     MOVE dmode_memory_to_memory TO DMODE
425 dsa_schedule_insert:
426     MOVE MEMORY 4, reconnect_dsa_head, 0 
428 ; And update the head pointer.
429     CALL dsa_to_scratch
430     MOVE dmode_ncr_to_memory TO DMODE   
431     MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
432     MOVE dmode_memory_to_memory TO DMODE
433 /* Temporarily, see what happens. */
434 #ifndef ORIGINAL
435     MOVE SCNTL2 & 0x7f TO SCNTL2
436     CLEAR ACK
437 #endif
438     WAIT DISCONNECT
439 #ifdef EVENTS
440     INT int_EVENT_DISCONNECT;
441 #endif
442 #if 0
443     INT int_debug_disconnected
444 #endif
445     JUMP schedule
446 #endif 
449 ; select
451 ; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
452 ;       On success, the current DSA structure is removed from the issue 
453 ;       queue.  Usually, this is entered as a fall-through from schedule,
454 ;       although the contingent allegiance handling code will write
455 ;       the select entry address to the DSP to restart a command as a 
456 ;       REQUEST SENSE.  A message is sent (usually IDENTIFY, although
457 ;       additional SDTR or WDTR messages may be sent).  COMMAND OUT
458 ;       is handled.
460 ; INPUTS : DSA - SCSI command, issue_dsa_head
462 ; CALLS : NOT OK
464 ; MODIFIES : SCRATCH, issue_dsa_head
466 ; EXITS : on reselection or selection, go to select_failed
467 ;       otherwise, RETURN so control is passed back to 
468 ;       dsa_begin.
471 ENTRY select
472 select:
474 #if 0
475 #ifdef EVENTS
476     INT int_EVENT_BEFORE_SELECT
477 #endif
478 #endif
480 #if 0
481 #ifdef DEBUG
482     INT int_debug_scheduled
483 #endif
484 #endif
485     CLEAR TARGET
487 ; XXX
489 ; In effect, SELECTION operations are backgrounded, with execution
490 ; continuing until code which waits for REQ or a fatal interrupt is 
491 ; encountered.
493 ; So, for more performance, we could overlap the code which removes 
494 ; the command from the NCRs issue queue with the selection, but 
495 ; at this point I don't want to deal with the error recovery.
498 #if (CHIP != 700) && (CHIP != 70066)
499     SELECT ATN FROM dsa_select, select_failed
500     JUMP select_msgout, WHEN MSG_OUT
501 ENTRY select_msgout
502 select_msgout:
503     MOVE FROM dsa_msgout, WHEN MSG_OUT
504 #else
505 ENTRY select_msgout
506     SELECT ATN 0, select_failed
507 select_msgout:
508     MOVE 0, 0, WHEN MSGOUT
509 #endif
511 #ifdef EVENTS
512    INT int_EVENT_SELECT
513 #endif
514    RETURN
517 ; select_done
519 ; PURPOSE: continue on to normal data transfer; called as the exit 
520 ;       point from dsa_begin.
522 ; INPUTS: dsa
524 ; CALLS: OK
528 select_done:
530 #ifdef DEBUG
531 ENTRY select_check_dsa
532 select_check_dsa:
533     INT int_debug_check_dsa
534 #endif
536 ; After a successful selection, we should get either a CMD phase or 
537 ; some transfer request negotiation message.
539     JUMP cmdout, WHEN CMD
540     INT int_err_unexpected_phase, WHEN NOT MSG_IN 
542 select_msg_in:
543     CALL msg_in, WHEN MSG_IN
544     JUMP select_msg_in, WHEN MSG_IN
546 cmdout:
547     INT int_err_unexpected_phase, WHEN NOT CMD
548 #if (CHIP == 700)
549     INT int_norm_selected
550 #endif
551 ENTRY cmdout_cmdout
552 cmdout_cmdout:
553 #if (CHIP != 700) && (CHIP != 70066)
554     MOVE FROM dsa_cmdout, WHEN CMD
555 #else
556     MOVE 0, 0, WHEN CMD
557 #endif /* (CHIP != 700) && (CHIP != 70066) */
560 ; data_transfer  
561 ; other_out
562 ; other_in
563 ; other_transfer
565 ; PURPOSE : handle the main data transfer for a SCSI command in 
566 ;       several parts.  In the first part, data_transfer, DATA_IN
567 ;       and DATA_OUT phases are allowed, with the user provided
568 ;       code (usually dynamically generated based on the scatter/gather
569 ;       list associated with a SCSI command) called to handle these 
570 ;       phases.
572 ;       After control has passed to one of the user provided 
573 ;       DATA_IN or DATA_OUT routines, back calls are made to 
574 ;       other_transfer_in or other_transfer_out to handle non-DATA IN
575 ;       and DATA OUT phases respectively, with the state of the active
576 ;       data pointer being preserved in TEMP.
578 ;       On completion, the user code passes control to other_transfer
579 ;       which causes DATA_IN and DATA_OUT to result in unexpected_phase
580 ;       interrupts so that data overruns may be trapped.
582 ; INPUTS : DSA - SCSI command
584 ; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
585 ;       other_transfer
587 ; MODIFIES : SCRATCH
589 ; EXITS : if STATUS IN is detected, signifying command completion,
590 ;       the NCR jumps to command_complete.  If MSG IN occurs, a 
591 ;       CALL is made to msg_in.  Otherwise, other_transfer runs in 
592 ;       an infinite loop.
593 ;       
595 ENTRY data_transfer
596 data_transfer:
597     JUMP cmdout_cmdout, WHEN CMD
598     CALL msg_in, WHEN MSG_IN
599     INT int_err_unexpected_phase, WHEN MSG_OUT
600     JUMP do_dataout, WHEN DATA_OUT
601     JUMP do_datain, WHEN DATA_IN
602     JUMP command_complete, WHEN STATUS
603     JUMP data_transfer
604 ENTRY end_data_transfer
605 end_data_transfer:
608 ; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain 
609 ; should be fixed up whenever the nexus changes so it can point to the 
610 ; correct routine for that command.
613 #if (CHIP != 700) && (CHIP != 70066)
614 ; Nasty jump to dsa->dataout
615 do_dataout:
616     CALL dsa_to_scratch
617     MOVE SCRATCH0 + dsa_dataout TO SCRATCH0     
618     MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
619     MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
620     MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
621     MOVE dmode_ncr_to_memory TO DMODE
622     MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
623     MOVE dmode_memory_to_memory TO DMODE
624 dataout_to_jump:
625     MOVE MEMORY 4, 0, dataout_jump + 4 
626 dataout_jump:
627     JUMP 0
629 ; Nasty jump to dsa->dsain
630 do_datain:
631     CALL dsa_to_scratch
632     MOVE SCRATCH0 + dsa_datain TO SCRATCH0      
633     MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
634     MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
635     MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
636     MOVE dmode_ncr_to_memory TO DMODE
637     MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
638     MOVE dmode_memory_to_memory TO DMODE                
639 ENTRY datain_to_jump
640 datain_to_jump:
641     MOVE MEMORY 4, 0, datain_jump + 4
642 #if 0
643     INT int_debug_datain
644 #endif
645 datain_jump:
646     JUMP 0
647 #endif /* (CHIP != 700) && (CHIP != 70066) */
650 ; Note that other_out and other_in loop until a non-data phase
651 ; is discovered, so we only execute return statements when we
652 ; can go on to the next data phase block move statement.
654 ENTRY other_out
655 other_out:
656 #if 0
657     INT 0x03ffdead
658 #endif
659     INT int_err_unexpected_phase, WHEN CMD
660     JUMP msg_in_restart, WHEN MSG_IN 
661     INT int_err_unexpected_phase, WHEN MSG_OUT
662     INT int_err_unexpected_phase, WHEN DATA_IN
663     JUMP command_complete, WHEN STATUS
664     JUMP other_out, WHEN NOT DATA_OUT
665     RETURN
667 ENTRY other_in
668 other_in:
669 #if 0
670     INT 0x03ffdead
671 #endif
672     INT int_err_unexpected_phase, WHEN CMD
673     JUMP msg_in_restart, WHEN MSG_IN 
674     INT int_err_unexpected_phase, WHEN MSG_OUT
675     INT int_err_unexpected_phase, WHEN DATA_OUT
676     JUMP command_complete, WHEN STATUS
677     JUMP other_in, WHEN NOT DATA_IN
678     RETURN
681 ENTRY other_transfer
682 other_transfer:
683     INT int_err_unexpected_phase, WHEN CMD
684     CALL msg_in, WHEN MSG_IN
685     INT int_err_unexpected_phase, WHEN MSG_OUT
686     INT int_err_unexpected_phase, WHEN DATA_OUT
687     INT int_err_unexpected_phase, WHEN DATA_IN
688     JUMP command_complete, WHEN STATUS
689     JUMP other_transfer
692 ; msg_in_restart
693 ; msg_in
694 ; munge_msg
696 ; PURPOSE : process messages from a target.  msg_in is called when the 
697 ;       caller hasn't read the first byte of the message.  munge_message
698 ;       is called when the caller has read the first byte of the message,
699 ;       and left it in SFBR.  msg_in_restart is called when the caller 
700 ;       hasn't read the first byte of the message, and wishes RETURN
701 ;       to transfer control back to the address of the conditional
702 ;       CALL instruction rather than to the instruction after it.
704 ;       Various int_* interrupts are generated when the host system
705 ;       needs to intervene, as is the case with SDTR, WDTR, and
706 ;       INITIATE RECOVERY messages.
708 ;       When the host system handles one of these interrupts,
709 ;       it can respond by reentering at reject_message, 
710 ;       which rejects the message and returns control to
711 ;       the caller of msg_in or munge_msg, accept_message
712 ;       which clears ACK and returns control, or reply_message
713 ;       which sends the message pointed to by the DSA 
714 ;       msgout_other table indirect field.
716 ;       DISCONNECT messages are handled by moving the command
717 ;       to the reconnect_dsa_queue.
719 ; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
720 ;       only)
722 ; CALLS : NO.  The TEMP register isn't backed up to allow nested calls.
724 ; MODIFIES : SCRATCH, DSA on DISCONNECT
726 ; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
727 ;       and normal return from message handlers running under
728 ;       Linux, control is returned to the caller.  Receipt
729 ;       of DISCONNECT messages pass control to dsa_schedule.
731 ENTRY msg_in_restart
732 msg_in_restart:
733 ; XXX - hackish
735 ; Since it's easier to debug changes to the statically 
736 ; compiled code, rather than the dynamically generated 
737 ; stuff, such as
739 ;       MOVE x, y, WHEN data_phase
740 ;       CALL other_z, WHEN NOT data_phase
741 ;       MOVE x, y, WHEN data_phase
743 ; I'd like to have certain routines (notably the message handler)
744 ; restart on the conditional call rather than the next instruction.
746 ; So, subtract 8 from the return address
748     MOVE TEMP0 + 0xf8 TO TEMP0
749     MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
750     MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
751     MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
753 ENTRY msg_in
754 msg_in:
755     MOVE 1, msg_buf, WHEN MSG_IN
757 munge_msg:
758     JUMP munge_extended, IF 0x01                ; EXTENDED MESSAGE
759     JUMP munge_2, IF 0x20, AND MASK 0xdf        ; two byte message
761 ; XXX - I've seen a handful of broken SCSI devices which fail to issue
762 ;       a SAVE POINTERS message before disconnecting in the middle of 
763 ;       a transfer, assuming that the DATA POINTER will be implicitly 
764 ;       restored.  
766 ; Historically, I've often done an implicit save when the DISCONNECT
767 ; message is processed.  We may want to consider having the option of 
768 ; doing that here. 
770     JUMP munge_save_data_pointer, IF 0x02       ; SAVE DATA POINTER
771     JUMP munge_restore_pointers, IF 0x03        ; RESTORE POINTERS 
772     JUMP munge_disconnect, IF 0x04              ; DISCONNECT
773     INT int_msg_1, IF 0x07                      ; MESSAGE REJECT
774     INT int_msg_1, IF 0x0f                      ; INITIATE RECOVERY
775 #ifdef EVENTS 
776     INT int_EVENT_SELECT_FAILED 
777 #endif
778     JUMP reject_message
780 munge_2:
781     JUMP reject_message
783 ; The SCSI standard allows targets to recover from transient 
784 ; error conditions by backing up the data pointer with a 
785 ; RESTORE POINTERS message.  
786 ;       
787 ; So, we must save and restore the _residual_ code as well as 
788 ; the current instruction pointer.  Because of this messiness,
789 ; it is simpler to put dynamic code in the dsa for this and to
790 ; just do a simple jump down there. 
793 munge_save_data_pointer:
794     MOVE DSA0 + dsa_save_data_pointer TO SFBR
795     MOVE SFBR TO SCRATCH0
796     MOVE DSA1 + 0xff TO SFBR WITH CARRY
797     MOVE SFBR TO SCRATCH1
798     MOVE DSA2 + 0xff TO SFBR WITH CARRY 
799     MOVE SFBR TO SCRATCH2
800     MOVE DSA3 + 0xff TO SFBR WITH CARRY
801     MOVE SFBR TO SCRATCH3
803     MOVE dmode_ncr_to_memory TO DMODE
804     MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
805     MOVE dmode_memory_to_memory TO DMODE
806 jump_dsa_save:
807     JUMP 0
809 munge_restore_pointers:
810     MOVE DSA0 + dsa_restore_pointers TO SFBR
811     MOVE SFBR TO SCRATCH0
812     MOVE DSA1 + 0xff TO SFBR WITH CARRY
813     MOVE SFBR TO SCRATCH1
814     MOVE DSA2 + 0xff TO SFBR WITH CARRY
815     MOVE SFBR TO SCRATCH2
816     MOVE DSA3 + 0xff TO SFBR WITH CARRY
817     MOVE SFBR TO SCRATCH3
819     MOVE dmode_ncr_to_memory TO DMODE
820     MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
821     MOVE dmode_memory_to_memory TO DMODE
822 jump_dsa_restore:
823     JUMP 0
826 munge_disconnect:
827 #if 0
828     INT int_debug_disconnect_msg
829 #endif
831 /* 
832  * Before, we overlapped processing with waiting for disconnect, but
833  * debugging was beginning to appear messy.  Temporarily move things
834  * to just before the WAIT DISCONNECT.
835  */
837 #ifdef ORIGINAL
838     MOVE SCNTL2 & 0x7f TO SCNTL2
839     CLEAR ACK
840 #endif
842 #if (CHIP != 700) && (CHIP != 70066)
843     JUMP dsa_schedule
844 #else
845     WAIT DISCONNECT
846     INT int_norm_disconnected
847 #endif
849 munge_extended:
850     CLEAR ACK
851     INT int_err_unexpected_phase, WHEN NOT MSG_IN
852     MOVE 1, msg_buf + 1, WHEN MSG_IN
853     JUMP munge_extended_2, IF 0x02
854     JUMP munge_extended_3, IF 0x03 
855     JUMP reject_message
857 munge_extended_2:
858     CLEAR ACK
859     MOVE 1, msg_buf + 2, WHEN MSG_IN
860     JUMP reject_message, IF NOT 0x02    ; Must be WDTR
861     CLEAR ACK
862     MOVE 1, msg_buf + 3, WHEN MSG_IN
863     INT int_msg_wdtr
865 munge_extended_3:
866     CLEAR ACK
867     MOVE 1, msg_buf + 2, WHEN MSG_IN
868     JUMP reject_message, IF NOT 0x01    ; Must be SDTR
869     CLEAR ACK
870     MOVE 2, msg_buf + 3, WHEN MSG_IN
871     INT int_msg_sdtr
873 ENTRY reject_message
874 reject_message:
875     SET ATN
876     CLEAR ACK
877     MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
878     RETURN
880 ENTRY accept_message
881 accept_message:
882     CLEAR ATN
883     CLEAR ACK
884     RETURN
886 ENTRY respond_message
887 respond_message:
888     SET ATN
889     CLEAR ACK
890     MOVE FROM dsa_msgout_other, WHEN MSG_OUT
891     RETURN
894 ; command_complete
896 ; PURPOSE : handle command termination when STATUS IN is detected by reading
897 ;       a status byte followed by a command termination message. 
899 ;       Normal termination results in an INTFLY instruction, and 
900 ;       the host system can pick out which command terminated by 
901 ;       examining the MESSAGE and STATUS buffers of all currently 
902 ;       executing commands;
904 ;       Abnormal (CHECK_CONDITION) termination results in an
905 ;       int_err_check_condition interrupt so that a REQUEST SENSE
906 ;       command can be issued out-of-order so that no other command
907 ;       clears the contingent allegiance condition.
908 ;       
910 ; INPUTS : DSA - command        
912 ; CALLS : OK
914 ; EXITS : On successful termination, control is passed to schedule.
915 ;       On abnormal termination, the user will usually modify the 
916 ;       DSA fields and corresponding buffers and return control
917 ;       to select.
920 ENTRY command_complete
921 command_complete:
922     MOVE FROM dsa_status, WHEN STATUS
923 #if (CHIP != 700) && (CHIP != 70066)
924     MOVE SFBR TO SCRATCH0               ; Save status
925 #endif /* (CHIP != 700) && (CHIP != 70066) */
926 ENTRY command_complete_msgin
927 command_complete_msgin:
928     MOVE FROM dsa_msgin, WHEN MSG_IN
929 ; Indicate that we should be expecting a disconnect
930     MOVE SCNTL2 & 0x7f TO SCNTL2
931     CLEAR ACK
932 #if (CHIP != 700) && (CHIP != 70066)
933     WAIT DISCONNECT
936 ; The SCSI specification states that when a UNIT ATTENTION condition
937 ; is pending, as indicated by a CHECK CONDITION status message,
938 ; the target shall revert to asynchronous transfers.  Since
939 ; synchronous transfers parameters are maintained on a per INITIATOR/TARGET 
940 ; basis, and returning control to our scheduler could work on a command
941 ; running on another lun on that target using the old parameters, we must
942 ; interrupt the host processor to get them changed, or change them ourselves.
944 ; Once SCSI-II tagged queueing is implemented, things will be even more
945 ; hairy, since contingent allegiance conditions exist on a per-target/lun
946 ; basis, and issuing a new command with a different tag would clear it.
947 ; In these cases, we must interrupt the host processor to get a request 
948 ; added to the HEAD of the queue with the request sense command, or we
949 ; must automatically issue the request sense command.
951 #if 0
952     MOVE SCRATCH0 TO SFBR                       
953     JUMP command_failed, IF 0x02
954 #endif
955     INTFLY
956 #endif /* (CHIP != 700) && (CHIP != 70066) */
957 #ifdef EVENTS
958     INT int_EVENT_COMPLETE
959 #endif
960 #if (CHIP != 700) && (CHIP != 70066)
961     JUMP schedule
962 command_failed:
963     INT int_err_check_condition
964 #else
965     INT int_norm_command_complete
966 #endif
969 ; wait_reselect
971 ; PURPOSE : This is essentially the idle routine, where control lands
972 ;       when there are no new processes to schedule.  wait_reselect
973 ;       waits for reselection, selection, and new commands.
975 ;       When a successful reselection occurs, with the aid 
976 ;       of fixed up code in each DSA, wait_reselect walks the 
977 ;       reconnect_dsa_queue, asking each dsa if the target ID
978 ;       and LUN match its.
980 ;       If a match is found, a call is made back to reselected_ok,
981 ;       which through the miracles of self modifying code, extracts
982 ;       the found DSA from the reconnect_dsa_queue and then 
983 ;       returns control to the DSAs thread of execution.
985 ; INPUTS : NONE
987 ; CALLS : OK
989 ; MODIFIES : DSA,
991 ; EXITS : On successful reselection, control is returned to the 
992 ;       DSA which called reselected_ok.  If the WAIT RESELECT
993 ;       was interrupted by a new commands arrival signaled by 
994 ;       SIG_P, control is passed to schedule.  If the NCR is 
995 ;       selected, the host system is interrupted with an 
996 ;       int_err_selected which is usually responded to by
997 ;       setting DSP to the target_abort address.
999 ENTRY wait_reselect
1000 wait_reselect:
1001 #ifdef EVENTS
1002     int int_EVENT_IDLE
1003 #endif
1004 #if 0
1005     int int_debug_idle
1006 #endif
1007     WAIT RESELECT wait_reselect_failed
1009 reselected:
1010 #ifdef EVENTS
1011     int int_EVENT_RESELECT
1012 #endif
1013     CLEAR TARGET
1014     MOVE dmode_memory_to_memory TO DMODE
1015     ; Read all data needed to reestablish the nexus - 
1016     MOVE 1, reselected_identify, WHEN MSG_IN
1017     ; We used to CLEAR ACK here.
1018 #if (CHIP != 700) && (CHIP != 70066)
1019 #if 0
1020     int int_debug_reselected
1021 #endif
1023     ; Point DSA at the current head of the disconnected queue.
1024     MOVE dmode_memory_to_ncr  TO DMODE
1025     MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
1026     MOVE dmode_memory_to_memory TO DMODE
1027     CALL scratch_to_dsa
1029     ; Fix the update-next pointer so that the reconnect_dsa_head
1030     ; pointer is the one that will be updated if this DSA is a hit 
1031     ; and we remove it from the queue.
1033     MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok + 8
1035 ENTRY reselected_check_next
1036 reselected_check_next:
1037 #if 0
1038     INT int_debug_reselect_check
1039 #endif
1040     ; Check for a NULL pointer.
1041     MOVE DSA0 TO SFBR
1042     JUMP reselected_not_end, IF NOT 0
1043     MOVE DSA1 TO SFBR
1044     JUMP reselected_not_end, IF NOT 0
1045     MOVE DSA2 TO SFBR
1046     JUMP reselected_not_end, IF NOT 0
1047     MOVE DSA3 TO SFBR
1048     JUMP reselected_not_end, IF NOT 0
1049     INT int_err_unexpected_reselect
1051 reselected_not_end:
1052     ;
1053     ; XXX the ALU is only eight bits wide, and the assembler
1054     ; wont do the dirt work for us.  As long as dsa_check_reselect
1055     ; is negative, we need to sign extend with 1 bits to the full
1056     ; 32 bit width of the address.
1057     ;
1058     ; A potential work around would be to have a known alignment 
1059     ; of the DSA structure such that the base address plus 
1060     ; dsa_check_reselect doesn't require carrying from bytes 
1061     ; higher than the LSB.
1062     ;
1064     MOVE DSA0 TO SFBR
1065     MOVE SFBR + dsa_check_reselect TO SCRATCH0
1066     MOVE DSA1 TO SFBR
1067     MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
1068     MOVE DSA2 TO SFBR
1069     MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
1070     MOVE DSA3 TO SFBR
1071     MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
1073     MOVE dmode_ncr_to_memory TO DMODE
1074     MOVE MEMORY 4, addr_scratch, reselected_check + 4
1075     MOVE dmode_memory_to_memory TO DMODE
1076 reselected_check:
1077     JUMP 0
1082 ENTRY reselected_ok
1083 reselected_ok:
1084     MOVE MEMORY 4, 0, 0                         ; Patched : first word
1085                                                 ;       is address of 
1086                                                 ;       successful dsa_next
1087                                                 ; Second word is last 
1088                                                 ;       unsuccessful dsa_next,
1089                                                 ;       starting with 
1090                                                 ;       dsa_reconnect_head
1091     ; We used to CLEAR ACK here.
1092 #if 0
1093     INT int_debug_reselected_ok
1094 #endif
1095 #ifdef DEBUG
1096     INT int_debug_check_dsa
1097 #endif
1098     RETURN                                      ; Return control to where
1099 #else
1100     INT int_norm_reselected
1101 #endif /* (CHIP != 700) && (CHIP != 70066) */
1103 selected:
1104     INT int_err_selected;
1107 ; A select or reselect failure can be caused by one of two conditions : 
1108 ; 1.  SIG_P was set.  This will be the case if the user has written
1109 ;       a new value to a previously NULL head of the issue queue.
1111 ; 2.  The NCR53c810 was selected or reselected by another device.
1113 ; 3.  The bus was already busy since we were selected or reselected
1114 ;       before starting the command.
1116 wait_reselect_failed:
1117 #ifdef EVENTS 
1118         INT int_EVENT_RESELECT_FAILED
1119 #endif
1120 ; Check selected bit.  
1121     MOVE SIST0 & 0x20 TO SFBR
1122     JUMP selected, IF 0x20
1123 ; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
1124     MOVE CTEST2 & 0x40 TO SFBR  
1125     JUMP schedule, IF 0x40
1126 ; Check connected bit.  
1127 ; FIXME: this needs to change if we support target mode
1128     MOVE ISTAT & 0x08 TO SFBR
1129     JUMP reselected, IF 0x08
1130 ; FIXME : Something bogus happened, and we shouldn't fail silently.
1131 #if 0
1132     JUMP schedule
1133 #else
1134     INT int_debug_panic
1135 #endif
1138 select_failed:
1139 #ifdef EVENTS
1140   int int_EVENT_SELECT_FAILED
1141 #endif
1142 ; Otherwise, mask the selected and reselected bits off SIST0
1143     MOVE SIST0 & 0x30 TO SFBR
1144     JUMP selected, IF 0x20
1145     JUMP reselected, IF 0x10 
1146 ; If SIGP is set, the user just gave us another command, and
1147 ; we should restart or return to the scheduler.
1148 ; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
1149     MOVE CTEST2 & 0x40 TO SFBR  
1150     JUMP select, IF 0x40
1151 ; Check connected bit.  
1152 ; FIXME: this needs to change if we support target mode
1153 ; FIXME: is this really necessary? 
1154     MOVE ISTAT & 0x08 TO SFBR
1155     JUMP reselected, IF 0x08
1156 ; FIXME : Something bogus happened, and we shouldn't fail silently.
1157 #if 0
1158     JUMP schedule
1159 #else
1160     INT int_debug_panic
1161 #endif
1164 ; test_1
1165 ; test_2
1167 ; PURPOSE : run some verification tests on the NCR.  test_1
1168 ;       copies test_src to test_dest and interrupts the host
1169 ;       processor, testing for cache coherency and interrupt
1170 ;       problems in the processes.
1172 ;       test_2 runs a command with offsets relative to the 
1173 ;       DSA on entry, and is useful for miscellaneous experimentation.
1176 ; Verify that interrupts are working correctly and that we don't 
1177 ; have a cache invalidation problem.
1179 ABSOLUTE test_src = 0, test_dest = 0
1180 ENTRY test_1
1181 test_1:
1182     MOVE MEMORY 4, test_src, test_dest
1183     INT int_test_1
1186 ; Run arbitrary commands, with test code establishing a DSA
1189 ENTRY test_2
1190 test_2:
1191     CLEAR TARGET
1192     SELECT ATN FROM 0, test_2_fail
1193     JUMP test_2_msgout, WHEN MSG_OUT
1194 ENTRY test_2_msgout
1195 test_2_msgout:
1196     MOVE FROM 8, WHEN MSG_OUT
1197     MOVE FROM 16, WHEN CMD 
1198     MOVE FROM 24, WHEN DATA_IN
1199     MOVE FROM 32, WHEN STATUS
1200     MOVE FROM 40, WHEN MSG_IN
1201     MOVE SCNTL2 & 0x7f TO SCNTL2
1202     CLEAR ACK
1203     WAIT DISCONNECT
1204 test_2_fail:
1205     INT int_test_2
1207 ENTRY debug_break
1208 debug_break:
1209     INT int_debug_break
1212 ; initiator_abort
1213 ; target_abort
1215 ; PURPOSE : Abort the currently established nexus from with initiator
1216 ;       or target mode.
1218 ;  
1220 ENTRY target_abort
1221 target_abort:
1222     SET TARGET
1223     DISCONNECT
1224     CLEAR TARGET
1225     JUMP schedule
1226     
1227 ENTRY initiator_abort
1228 initiator_abort:
1229     SET ATN
1231 ; The SCSI-I specification says that targets may go into MSG out at 
1232 ; their leisure upon receipt of the ATN single.  On all versions of the 
1233 ; specification, we can't change phases until REQ transitions true->false, 
1234 ; so we need to sink/source one byte of data to allow the transition.
1236 ; For the sake of safety, we'll only source one byte of data in all 
1237 ; cases, but to accommodate the SCSI-I dain bramage, we'll sink an  
1238 ; arbitrary number of bytes.
1239     JUMP spew_cmd, WHEN CMD
1240     JUMP eat_msgin, WHEN MSG_IN
1241     JUMP eat_datain, WHEN DATA_IN
1242     JUMP eat_status, WHEN STATUS
1243     JUMP spew_dataout, WHEN DATA_OUT
1244     JUMP sated
1245 spew_cmd:
1246     MOVE 1, NCR53c7xx_zero, WHEN CMD
1247     JUMP sated
1248 eat_msgin:
1249     MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
1250     JUMP eat_msgin, WHEN MSG_IN
1251     JUMP sated
1252 eat_status:
1253     MOVE 1, NCR53c7xx_sink, WHEN STATUS
1254     JUMP eat_status, WHEN STATUS
1255     JUMP sated
1256 eat_datain:
1257     MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
1258     JUMP eat_datain, WHEN DATA_IN
1259     JUMP sated
1260 spew_dataout:
1261     MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
1262 sated:
1263     MOVE SCNTL2 & 0x7f TO SCNTL2
1264     MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
1265     WAIT DISCONNECT
1266     INT int_norm_aborted
1269 ; dsa_to_scratch
1270 ; scratch_to_dsa
1272 ; PURPOSE :
1273 ;       The NCR chips cannot do a move memory instruction with the DSA register 
1274 ;       as the source or destination.  So, we provide a couple of subroutines
1275 ;       that let us switch between the DSA register and scratch register.
1277 ;       Memory moves to/from the DSPS  register also don't work, but we 
1278 ;       don't use them.
1283 dsa_to_scratch:
1284     MOVE DSA0 TO SFBR
1285     MOVE SFBR TO SCRATCH0
1286     MOVE DSA1 TO SFBR
1287     MOVE SFBR TO SCRATCH1
1288     MOVE DSA2 TO SFBR
1289     MOVE SFBR TO SCRATCH2
1290     MOVE DSA3 TO SFBR
1291     MOVE SFBR TO SCRATCH3
1292     RETURN
1294 scratch_to_dsa:
1295     MOVE SCRATCH0 TO SFBR
1296     MOVE SFBR TO DSA0
1297     MOVE SCRATCH1 TO SFBR
1298     MOVE SFBR TO DSA1
1299     MOVE SCRATCH2 TO SFBR
1300     MOVE SFBR TO DSA2
1301     MOVE SCRATCH3 TO SFBR
1302     MOVE SFBR TO DSA3
1303     RETURN
1304