1#undef DEBUG
2#undef EVENTS
3#undef NO_SELECTION_TIMEOUT
4#define BIG_ENDIAN
5
6; 53c710 driver.  Modified from Drew Eckhardts driver
7; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
8;
9; I have left the script for the 53c8xx family in here, as it is likely
10; to be useful to see what I changed when bug hunting.
11
12; NCR 53c810 driver, main script
13; Sponsored by 
14;	iX Multiuser Multitasking Magazine
15;	hm@ix.de
16;
17; Copyright 1993, 1994, 1995 Drew Eckhardt
18;      Visionary Computing 
19;      (Unix and Linux consulting and custom programming)
20;      drew@PoohSticks.ORG
21;      +1 (303) 786-7975
22;
23; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
24;
25; PRE-ALPHA
26;
27; For more information, please consult 
28;
29; NCR 53C810
30; PCI-SCSI I/O Processor
31; Data Manual
32;
33; NCR 53C710 
34; SCSI I/O Processor
35; Programmers Guide
36;
37; NCR Microelectronics
38; 1635 Aeroplaza Drive
39; Colorado Springs, CO 80916
40; 1+ (719) 578-3400
41;
42; Toll free literature number
43; +1 (800) 334-5454
44;
45; IMPORTANT : This code is self modifying due to the limitations of 
46;	the NCR53c7,8xx series chips.  Persons debugging this code with
47;	the remote debugger should take this into account, and NOT set
48;	breakpoints in modified instructions.
49;
50; Design:
51; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 
52; microcontroller using a simple instruction set.   
53;
54; So, to minimize the effects of interrupt latency, and to maximize 
55; throughput, this driver offloads the practical maximum amount 
56; of processing to the SCSI chip while still maintaining a common
57; structure.
58;
59; Where tradeoffs were needed between efficiency on the older
60; chips and the newer NCR53c800 series, the NCR53c800 series 
61; was chosen.
62;
63; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
64; automate SCSI transfers without host processor intervention, this 
65; isn't the case with the NCR53c710 and newer chips which allow 
66;
67; - reads and writes to the internal registers from within the SCSI
68; 	scripts, allowing the SCSI SCRIPTS(tm) code to save processor
69; 	state so that multiple threads of execution are possible, and also
70; 	provide an ALU for loop control, etc.
71; 
72; - table indirect addressing for some instructions. This allows 
73;	pointers to be located relative to the DSA ((Data Structure
74;	Address) register.
75;
76; These features make it possible to implement a mailbox style interface,
77; where the same piece of code is run to handle I/O for multiple threads
78; at once minimizing our need to relocate code.  Since the NCR53c700/
79; NCR53c800 series have a unique combination of features, making a 
80; a standard ingoing/outgoing mailbox system, costly, I've modified it.
81;
82; - Mailboxes are a mixture of code and data.  This lets us greatly
83; 	simplify the NCR53c810 code and do things that would otherwise
84;	not be possible.
85;
86; The saved data pointer is now implemented as follows :
87;
88; 	Control flow has been architected such that if control reaches
89;	munge_save_data_pointer, on a restore pointers message or 
90;	reconnection, a jump to the address formerly in the TEMP register
91;	will allow the SCSI command to resume execution.
92;
93
94;
95; Note : the DSA structures must be aligned on 32 bit boundaries,
96; since the source and destination of MOVE MEMORY instructions 
97; must share the same alignment and this is the alignment of the
98; NCR registers.
99;
100
101; For some systems (MVME166, for example) dmode is always the same, so don't
102; waste time writing it
103
104#if 1
105#define DMODE_MEMORY_TO_NCR
106#define DMODE_MEMORY_TO_MEMORY
107#define DMODE_NCR_TO_MEMORY
108#else
109#define DMODE_MEMORY_TO_NCR    MOVE dmode_memory_to_ncr TO DMODE
110#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
111#define DMODE_NCR_TO_MEMORY    MOVE dmode_ncr_to_memory TO DMODE
112#endif
113
114ABSOLUTE dsa_temp_lun = 0		; Patch to lun for current dsa
115ABSOLUTE dsa_temp_next = 0		; Patch to dsa next for current dsa
116ABSOLUTE dsa_temp_addr_next = 0		; Patch to address of dsa next address 
117					; 	for current dsa
118ABSOLUTE dsa_temp_sync = 0		; Patch to address of per-target
119					;	sync routine
120ABSOLUTE dsa_sscf_710 = 0		; Patch to address of per-target
121					;	sscf value (53c710)
122ABSOLUTE dsa_temp_target = 0		; Patch to id for current dsa
123ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
124					; 	saved data pointer
125ABSOLUTE dsa_temp_addr_residual = 0	; Patch to address of per-command
126					;	current residual code
127ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
128					; saved residual code
129ABSOLUTE dsa_temp_addr_new_value = 0	; Address of value for JUMP operand
130ABSOLUTE dsa_temp_addr_array_value = 0 	; Address to copy to
131ABSOLUTE 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
175ENTRY dsa_code_template
176dsa_code_template:
177ENTRY dsa_code_begin
178dsa_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.
207ENTRY dsa_code_fix_jump
208dsa_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;
215wrong_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
240ABSOLUTE dsa_save_data_pointer = 0
241ENTRY dsa_code_save_data_pointer
242dsa_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
267ABSOLUTE dsa_restore_pointers = 0
268ENTRY dsa_code_restore_pointers
269dsa_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
295ABSOLUTE dsa_check_reselect = 0
296; dsa_check_reselect determines whether or not the current target and
297; lun match the current DSA
298ENTRY dsa_code_check_reselect
299dsa_code_check_reselect:
300#if (CHIP == 710)
301	/* Arrives here with DSA correct */
302	/* Assumes we are always ID 7 */
303	MOVE LCRC TO SFBR		; LCRC has our ID and his ID bits set
304	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
305#else
306	MOVE SSID TO SFBR		; SSID contains 3 bit target ID
307; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
308	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
309#endif
310;
311; Hack - move to scratch first, since SFBR is not writeable
312; 	via the CPU and hence a MOVE MEMORY instruction.
313;
314	DMODE_MEMORY_TO_NCR
315	MOVE MEMORY 1, reselected_identify, addr_scratch
316	DMODE_MEMORY_TO_MEMORY
317#ifdef BIG_ENDIAN
318	; BIG ENDIAN ON MVME16x
319	MOVE SCRATCH3 TO SFBR
320#else
321	MOVE SCRATCH0 TO SFBR
322#endif
323; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
324; Are you sure about that?  richard@sleepie.demon.co.uk
325	JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
326;		Patch the MOVE MEMORY INSTRUCTION such that
327;		the source address is the address of this dsa's
328;		next pointer.
329	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
330	CALL reselected_ok
331#if (CHIP == 710)
332;	Restore DSA following memory moves in reselected_ok
333;	dsa_temp_sync doesn't really care about DSA, but it has an
334;	optional debug INT so a valid DSA is a good idea.
335	MOVE MEMORY 4, saved_dsa, addr_dsa
336#endif
337	CALL dsa_temp_sync	
338; Release ACK on the IDENTIFY message _after_ we've set the synchronous 
339; transfer parameters! 
340	CLEAR ACK
341; Implicitly restore pointers on reselection, so a RETURN
342; will transfer control back to the right spot.
343    	CALL REL (dsa_code_restore_pointers)
344    	RETURN
345ENTRY dsa_zero
346dsa_zero:
347ENTRY dsa_code_template_end
348dsa_code_template_end:
349
350; Perform sanity check for dsa_fields_start == dsa_code_template_end - 
351; dsa_zero, puke.
352
353ABSOLUTE dsa_fields_start =  0	; Sanity marker
354				; 	pad 48 bytes (fix this RSN)
355ABSOLUTE dsa_next = 48		; len 4 Next DSA
356 				; del 4 Previous DSA address
357ABSOLUTE dsa_cmnd = 56		; len 4 Scsi_Cmnd * for this thread.
358ABSOLUTE dsa_select = 60	; len 4 Device ID, Period, Offset for 
359			 	;	table indirect select
360ABSOLUTE dsa_msgout = 64	; len 8 table indirect move parameter for 
361				;       select message
362ABSOLUTE dsa_cmdout = 72	; len 8 table indirect move parameter for 
363				;	command
364ABSOLUTE dsa_dataout = 80	; len 4 code pointer for dataout
365ABSOLUTE dsa_datain = 84	; len 4 code pointer for datain
366ABSOLUTE dsa_msgin = 88		; len 8 table indirect move for msgin
367ABSOLUTE dsa_status = 96 	; len 8 table indirect move for status byte
368ABSOLUTE dsa_msgout_other = 104	; len 8 table indirect for normal message out
369				; (Synchronous transfer negotiation, etc).
370ABSOLUTE dsa_end = 112
371
372ABSOLUTE 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
376ABSOLUTE reconnect_dsa_head = 0	; Link list of DSAs which can reconnect
377ABSOLUTE 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
381ABSOLUTE dmode_memory_to_memory = 0x0
382ABSOLUTE dmode_memory_to_ncr = 0x0
383ABSOLUTE dmode_ncr_to_memory = 0x0
384
385ABSOLUTE addr_scratch = 0x0
386ABSOLUTE addr_temp = 0x0
387#if (CHIP == 710)
388ABSOLUTE saved_dsa = 0x0
389ABSOLUTE emulfly = 0x0
390ABSOLUTE 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 
407ABSOLUTE int_err_unexpected_phase = 0x00000000	; Unexpected phase encountered
408ABSOLUTE int_err_selected = 0x00010000		; SELECTED (nee RESELECTED)
409ABSOLUTE int_err_unexpected_reselect = 0x00020000 
410ABSOLUTE int_err_check_condition = 0x00030000	
411ABSOLUTE int_err_no_phase = 0x00040000
412ABSOLUTE int_msg_wdtr = 0x01000000		; WDTR message received
413ABSOLUTE int_msg_sdtr = 0x01010000		; SDTR received
414ABSOLUTE int_msg_1 = 0x01020000			; single byte special message
415						; received
416
417ABSOLUTE int_norm_select_complete = 0x02000000	; Select complete, reprogram
418						; registers.
419ABSOLUTE int_norm_reselect_complete = 0x02010000	; Nexus established
420ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
421ABSOLUTE int_norm_disconnected = 0x02030000	; Disconnected 
422ABSOLUTE int_norm_aborted =0x02040000		; Aborted *dsa
423ABSOLUTE int_norm_reset = 0x02050000		; Generated BUS reset.
424ABSOLUTE int_norm_emulateintfly = 0x02060000	; 53C710 Emulated intfly
425ABSOLUTE int_debug_break = 0x03000000		; Break point
426#ifdef DEBUG
427ABSOLUTE int_debug_scheduled = 0x03010000	; new I/O scheduled 
428ABSOLUTE int_debug_idle = 0x03020000		; scheduler is idle
429ABSOLUTE int_debug_dsa_loaded = 0x03030000	; dsa reloaded
430ABSOLUTE int_debug_reselected = 0x03040000	; NCR reselected
431ABSOLUTE int_debug_head = 0x03050000		; issue head overwritten
432ABSOLUTE int_debug_disconnected = 0x03060000	; disconnected
433ABSOLUTE int_debug_disconnect_msg = 0x03070000	; got message to disconnect
434ABSOLUTE int_debug_dsa_schedule = 0x03080000	; in dsa_schedule
435ABSOLUTE int_debug_reselect_check = 0x03090000  ; Check for reselection of DSA
436ABSOLUTE int_debug_reselected_ok = 0x030a0000 	; Reselection accepted
437#endif
438ABSOLUTE int_debug_panic = 0x030b0000		; Panic driver
439#ifdef DEBUG
440ABSOLUTE int_debug_saved = 0x030c0000 		; save/restore pointers
441ABSOLUTE int_debug_restored = 0x030d0000
442ABSOLUTE int_debug_sync = 0x030e0000		; Sanity check synchronous 
443						; parameters. 
444ABSOLUTE int_debug_datain = 0x030f0000		; going into data in phase 
445						; now.
446ABSOLUTE int_debug_check_dsa = 0x03100000	; Sanity check DSA against
447						; SDID.
448#endif
449
450ABSOLUTE int_test_1 = 0x04000000		; Test 1 complete
451ABSOLUTE int_test_2 = 0x04010000		; Test 2 complete
452ABSOLUTE 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
459ABSOLUTE int_EVENT_SELECT = 0
460ABSOLUTE int_EVENT_DISCONNECT = 0
461ABSOLUTE int_EVENT_RESELECT = 0
462ABSOLUTE int_EVENT_COMPLETE = 0
463ABSOLUTE int_EVENT_IDLE = 0
464ABSOLUTE int_EVENT_SELECT_FAILED = 0
465ABSOLUTE int_EVENT_BEFORE_SELECT = 0
466ABSOLUTE int_EVENT_RESELECT_FAILED = 0
467#endif
468						
469ABSOLUTE NCR53c7xx_msg_abort = 0	; Pointer to abort message
470ABSOLUTE NCR53c7xx_msg_reject = 0       ; Pointer to reject message
471ABSOLUTE NCR53c7xx_zero	= 0		; long with zero in it, use for source
472ABSOLUTE NCR53c7xx_sink = 0		; long to dump worthless data in
473ABSOLUTE NOP_insn = 0			; NOP instruction
474
475; Pointer to message, potentially multi-byte
476ABSOLUTE msg_buf = 0
477
478; Pointer to holding area for reselection information
479ABSOLUTE reselected_identify = 0
480ABSOLUTE 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
503ENTRY dsa_schedule
504dsa_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
530dsa_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
588ENTRY select
589select:
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
622ENTRY select_msgout
623select_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
630ENTRY select_msgout
631    SELECT ATN 0, select_failed
632select_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
653select_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
660ENTRY select_check_dsa
661select_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
671select_msg_in:
672    CALL msg_in, WHEN MSG_IN
673    JUMP select_msg_in, WHEN MSG_IN
674
675cmdout:
676    INT int_err_unexpected_phase, WHEN NOT CMD
677#if (CHIP == 700)
678    INT int_norm_selected
679#endif
680ENTRY cmdout_cmdout
681cmdout_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
724ENTRY data_transfer
725data_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
733ENTRY end_data_transfer
734end_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
744do_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
757dataout_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
763dataout_jump:
764    JUMP 0
765
766; Nasty jump to dsa->dsain
767do_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
780ENTRY datain_to_jump
781datain_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
790datain_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
799ENTRY other_out
800other_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
815ENTRY other_in
816other_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
832ENTRY other_transfer
833other_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;
886ENTRY msg_in_restart
887msg_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
908ENTRY msg_in
909msg_in:
910    MOVE 1, msg_buf, WHEN MSG_IN
911
912munge_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
935munge_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
948munge_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
975jump_dsa_save:
976    JUMP 0
977
978munge_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
995jump_dsa_restore:
996    JUMP 0
997
998
999munge_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
1026munge_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
1034munge_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
1042munge_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
1050ENTRY reject_message
1051reject_message:
1052    SET ATN
1053    CLEAR ACK
1054    MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
1055    RETURN
1056
1057ENTRY accept_message
1058accept_message:
1059    CLEAR ATN
1060    CLEAR ACK
1061    RETURN
1062
1063ENTRY respond_message
1064respond_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
1097ENTRY command_complete
1098command_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) */
1103ENTRY command_complete_msgin
1104command_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
1166command_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
1203ENTRY wait_reselect
1204wait_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
1213reselected:
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
1247ENTRY reselected_check_next
1248reselected_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
1263reselected_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
1292reselected_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
1309ENTRY reselected_ok
1310reselected_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
1320reselected_ok_patch:
1321    MOVE MEMORY 4, 0, 0
1322reselected_ok_jump:
1323    JUMP 0
1324#else
1325ENTRY reselected_ok
1326reselected_ok:
1327reselected_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
1348selected:
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
1361wait_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
1387select_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
1437ABSOLUTE test_src = 0, test_dest = 0
1438ENTRY test_1
1439test_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 
1447ENTRY test_2
1448test_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
1460ENTRY test_2_msgout
1461test_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
1476test_2_fail:
1477#if (CHIP == 710)
1478    ; Disable selection timer
1479    MOVE CTEST7 | 0x10 TO CTEST7
1480#endif
1481    INT int_test_2
1482
1483ENTRY debug_break
1484debug_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
1496ENTRY target_abort
1497target_abort:
1498    SET TARGET
1499    DISCONNECT
1500    CLEAR TARGET
1501    JUMP schedule
1502    
1503ENTRY initiator_abort
1504initiator_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
1521spew_cmd:
1522    MOVE 1, NCR53c7xx_zero, WHEN CMD
1523    JUMP sated
1524eat_msgin:
1525    MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
1526    JUMP eat_msgin, WHEN MSG_IN
1527    JUMP sated
1528eat_status:
1529    MOVE 1, NCR53c7xx_sink, WHEN STATUS
1530    JUMP eat_status, WHEN STATUS
1531    JUMP sated
1532eat_datain:
1533    MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
1534    JUMP eat_datain, WHEN DATA_IN
1535    JUMP sated
1536spew_dataout:
1537    MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
1538sated:
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 
1562dsa_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
1573scratch_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
1589jump_temp:
1590    JUMP 0
1591#endif
1592