3 ; NCR 53c810 driver, main script
5 ; iX Multiuser Multitasking Magazine
8 ; Copyright 1993, 1994, 1995 Drew Eckhardt
10 ; (Unix and Linux consulting and custom programming)
14 ; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
18 ; For more information, please consult
21 ; PCI-SCSI I/O Processor
28 ; NCR Microelectronics
29 ; 1635 Aeroplaza Drive
30 ; Colorado Springs, CO 80916
33 ; Toll free literature number
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.
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
50 ; Where tradeoffs were needed between efficiency on the older
51 ; chips and the newer NCR53c800 series, the NCR53c800 series
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.
63 ; - table indirect addressing for some instructions. This allows
64 ; pointers to be located relative to the DSA ((Data Structure
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
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
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
96 ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
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
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
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) {
136 ; if (target_id == dsa->id && target_lun == dsa->lun) {
143 ; error (int_err_unexpected_reselect);
145 ; longjmp (dsa->jump_resume, 0);
149 #if (CHIP != 700) && (CHIP != 70066)
150 ; Define DSA structure used for mailboxes
151 ENTRY dsa_code_template
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
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.
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
171 MOVE MEMORY 4, NOP_insn, 0
174 ; wrong_dsa loads the DSA register with the value of the dsa_next
178 ; Patch the MOVE MEMORY INSTRUCTION such that
179 ; the destination address is the address of the OLD
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
189 MOVE MEMORY 4, dsa_temp_next, addr_scratch
190 MOVE dmode_memory_to_memory TO DMODE
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
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
217 INT int_debug_restored
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
242 MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok + 4
245 ; Release ACK on the IDENTIFY message _after_ we've set the synchronous
246 ; transfer parameters!
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)
254 ENTRY dsa_code_template_end
255 dsa_code_template_end:
257 ; Perform sanity check for dsa_fields_start == dsa_code_template_end -
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
269 ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
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 */
298 ; 0 handle error condition
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
319 ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
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
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
339 ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
341 ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers
342 ABSOLUTE int_debug_restored = 0x030d0000
343 ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous
345 ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase
347 ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against
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
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
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
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)
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.
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
407 INT int_debug_dsa_schedule
411 ; Calculate the address of the next pointer within the DSA
412 ; structure of the command that is currently disconnecting
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
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
426 MOVE MEMORY 4, reconnect_dsa_head, 0
428 ; And update the head pointer.
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. */
435 MOVE SCNTL2 & 0x7f TO SCNTL2
440 INT int_EVENT_DISCONNECT;
443 INT int_debug_disconnected
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
460 ; INPUTS : DSA - SCSI command, issue_dsa_head
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
476 INT int_EVENT_BEFORE_SELECT
482 INT int_debug_scheduled
489 ; In effect, SELECTION operations are backgrounded, with execution
490 ; continuing until code which waits for REQ or a fatal interrupt is
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
503 MOVE FROM dsa_msgout, WHEN MSG_OUT
506 SELECT ATN 0, select_failed
508 MOVE 0, 0, WHEN MSGOUT
519 ; PURPOSE: continue on to normal data transfer; called as the exit
520 ; point from dsa_begin.
531 ENTRY select_check_dsa
533 INT int_debug_check_dsa
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
543 CALL msg_in, WHEN MSG_IN
544 JUMP select_msg_in, WHEN MSG_IN
547 INT int_err_unexpected_phase, WHEN NOT CMD
549 INT int_norm_selected
553 #if (CHIP != 700) && (CHIP != 70066)
554 MOVE FROM dsa_cmdout, WHEN CMD
557 #endif /* (CHIP != 700) && (CHIP != 70066) */
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
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
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
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
604 ENTRY 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
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
625 MOVE MEMORY 4, 0, dataout_jump + 4
629 ; Nasty jump to dsa->dsain
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
641 MOVE MEMORY 4, 0, datain_jump + 4
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.
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
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
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
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
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.
735 ; Since it's easier to debug changes to the statically
736 ; compiled code, rather than the dynamically generated
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
755 MOVE 1, msg_buf, WHEN MSG_IN
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
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
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
776 INT int_EVENT_SELECT_FAILED
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.
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
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
828 INT int_debug_disconnect_msg
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.
838 MOVE SCNTL2 & 0x7f TO SCNTL2
842 #if (CHIP != 700) && (CHIP != 70066)
846 INT int_norm_disconnected
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
859 MOVE 1, msg_buf + 2, WHEN MSG_IN
860 JUMP reject_message, IF NOT 0x02 ; Must be WDTR
862 MOVE 1, msg_buf + 3, WHEN MSG_IN
867 MOVE 1, msg_buf + 2, WHEN MSG_IN
868 JUMP reject_message, IF NOT 0x01 ; Must be SDTR
870 MOVE 2, msg_buf + 3, WHEN MSG_IN
877 MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
886 ENTRY respond_message
890 MOVE FROM dsa_msgout_other, WHEN MSG_OUT
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.
910 ; INPUTS : DSA - command
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
920 ENTRY 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
932 #if (CHIP != 700) && (CHIP != 70066)
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.
952 MOVE SCRATCH0 TO SFBR
953 JUMP command_failed, IF 0x02
956 #endif /* (CHIP != 700) && (CHIP != 70066) */
958 INT int_EVENT_COMPLETE
960 #if (CHIP != 700) && (CHIP != 70066)
963 INT int_err_check_condition
965 INT int_norm_command_complete
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
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.
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.
1007 WAIT RESELECT wait_reselect_failed
1011 int int_EVENT_RESELECT
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)
1020 int int_debug_reselected
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
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:
1038 INT int_debug_reselect_check
1040 ; Check for a NULL pointer.
1042 JUMP reselected_not_end, IF NOT 0
1044 JUMP reselected_not_end, IF NOT 0
1046 JUMP reselected_not_end, IF NOT 0
1048 JUMP reselected_not_end, IF NOT 0
1049 INT int_err_unexpected_reselect
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.
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.
1065 MOVE SFBR + dsa_check_reselect TO SCRATCH0
1067 MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
1069 MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
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
1084 MOVE MEMORY 4, 0, 0 ; Patched : first word
1086 ; successful dsa_next
1087 ; Second word is last
1088 ; unsuccessful dsa_next,
1090 ; dsa_reconnect_head
1091 ; We used to CLEAR ACK here.
1093 INT int_debug_reselected_ok
1096 INT int_debug_check_dsa
1098 RETURN ; Return control to where
1100 INT int_norm_reselected
1101 #endif /* (CHIP != 700) && (CHIP != 70066) */
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:
1118 INT int_EVENT_RESELECT_FAILED
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.
1140 int int_EVENT_SELECT_FAILED
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.
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
1182 MOVE MEMORY 4, test_src, test_dest
1186 ; Run arbitrary commands, with test code establishing a DSA
1192 SELECT ATN FROM 0, test_2_fail
1193 JUMP test_2_msgout, WHEN MSG_OUT
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
1215 ; PURPOSE : Abort the currently established nexus from with initiator
1227 ENTRY initiator_abort
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
1246 MOVE 1, NCR53c7xx_zero, WHEN CMD
1249 MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
1250 JUMP eat_msgin, WHEN MSG_IN
1253 MOVE 1, NCR53c7xx_sink, WHEN STATUS
1254 JUMP eat_status, WHEN STATUS
1257 MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
1258 JUMP eat_datain, WHEN DATA_IN
1261 MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
1263 MOVE SCNTL2 & 0x7f TO SCNTL2
1264 MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
1266 INT int_norm_aborted
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
1285 MOVE SFBR TO SCRATCH0
1287 MOVE SFBR TO SCRATCH1
1289 MOVE SFBR TO SCRATCH2
1291 MOVE SFBR TO SCRATCH3
1295 MOVE SCRATCH0 TO SFBR
1297 MOVE SCRATCH1 TO SFBR
1299 MOVE SCRATCH2 TO SFBR
1301 MOVE SCRATCH3 TO SFBR