summaryrefslogtreecommitdiff
path: root/os/pc/sd53c8xx.n
diff options
context:
space:
mode:
Diffstat (limited to 'os/pc/sd53c8xx.n')
-rw-r--r--os/pc/sd53c8xx.n448
1 files changed, 448 insertions, 0 deletions
diff --git a/os/pc/sd53c8xx.n b/os/pc/sd53c8xx.n
new file mode 100644
index 00000000..d9dc2fa1
--- /dev/null
+++ b/os/pc/sd53c8xx.n
@@ -0,0 +1,448 @@
+// NCR 53c8xx driver for Plan 9
+// Nigel Roles (nigel@9fs.org)
+//
+// Microcode
+//
+// 27/5/02 Fixed problems with transfers >= 256 * 512
+//
+// 13/3/01 Fixed microcode to support targets > 7
+//
+
+extern scsi_id_buf
+extern msg_out_buf
+extern cmd_buf
+extern data_buf
+extern status_buf
+extern msgin_buf
+extern dsa_0
+extern dsa_1
+extern dsa_head
+extern ssid_mask
+
+SIR_MSG_IO_COMPLETE = 0
+error_not_cmd_complete = 1
+error_disconnected = 2
+error_reselected = 3
+error_unexpected_phase = 4
+error_weird_message = 5
+SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT = 6
+error_not_identify_after_reselect = 7
+error_too_much_data = 8
+error_too_little_data = 9
+SIR_MSG_REJECT = 10
+SIR_MSG_SDTR = 11
+SIR_EV_RESPONSE_OK = 12
+error_sigp_set = 13
+SIR_EV_PHASE_SWITCH_AFTER_ID = 14
+SIR_MSG_WDTR = 15
+SIR_MSG_IGNORE_WIDE_RESIDUE = 16
+SIR_NOTIFY_DISC = 100
+SIR_NOTIFY_RESELECT = 101
+SIR_NOTIFY_MSG_IN = 102
+SIR_NOTIFY_STATUS = 103
+SIR_NOTIFY_DUMP = 104
+SIR_NOTIFY_DUMP2 = 105
+SIR_NOTIFY_SIGP = 106
+SIR_NOTIFY_ISSUE = 107
+SIR_NOTIFY_WAIT_RESELECT = 108
+SIR_NOTIFY_ISSUE_CHECK = 109
+SIR_NOTIFY_DUMP_NEXT_CODE = 110
+SIR_NOTIFY_COMMAND = 111
+SIR_NOTIFY_DATA_IN = 112
+SIR_NOTIFY_DATA_OUT = 113
+SIR_NOTIFY_BLOCK_DATA_IN = 114
+SIR_NOTIFY_WSR = 115
+SIR_NOTIFY_LOAD_SYNC = 116
+SIR_NOTIFY_RESELECTED_ON_SELECT = 117
+
+STATE_FREE = 0
+STATE_ALLOCATED = 1
+STATE_ISSUE = 2
+STATE_DISCONNECTED = 3
+STATE_DONE = 4
+
+RESULT_OK = 0
+
+MSG_IDENTIFY = 0x80
+MSG_DISCONNECT = 0x04
+MSG_SAVE_DATA_POINTER = 0x02
+MSG_RESTORE_POINTERS = 0x03
+MSG_IGNORE_WIDE_RESIDUE = 0x23
+X_MSG = 0x01
+X_MSG_SDTR = 0x01
+X_MSG_WDTR = 0x03
+MSG_REJECT = 0x07
+
+BSIZE = 512
+//BSIZE=4096
+
+idle:
+ jump wait_for_reselection
+start:
+ call load_sync
+// move 13 to ctest0
+// int SIR_NOTIFY_ISSUE
+ clear target
+ select atn from scsi_id_buf, reselected_on_select // do I need to clear ATN here?
+ jump start1, when msg_in
+start1:
+// move 14 to ctest0
+ move from msg_out_buf, when msg_out
+id_out_mismatch:
+ jump start1, when msg_out // repeat on parity grounds
+ jump to_decisions, when not cmd
+cmd_phase:
+// int SIR_NOTIFY_COMMAND
+ clear atn
+ move from cmd_buf, when cmd
+cmd_out_mismatch:
+ jump to_decisions, when not data_in
+data_in_phase:
+ move memory 4, state, scratcha
+ move memory 4, dmaaddr, scratchb
+// int SIR_NOTIFY_DATA_IN
+data_in_block_loop:
+ move scratcha2 to sfbr
+ jump data_in_normal, if 0
+// int SIR_NOTIFY_BLOCK_DATA_IN
+ move BSIZE, ptr dmaaddr, when data_in // transfer BSIZE bytes
+data_in_block_mismatch:
+ move scratchb1 + BSIZE / 256 to scratchb1 // add BSIZE to scratchb
+ move scratchb2 + 0 to scratchb2 with carry
+ move scratchb3 + 0 to scratchb3 with carry
+ move scratcha2 + 255 to scratcha2 // sub one from block count
+ move memory 4, scratchb, dmaaddr // save latest dmaddr
+ jump data_in_block_loop, when data_in
+ move memory 4, scratcha, state // save latest state
+ call save_state
+ jump to_decisions
+data_block_mismatch_recover:
+ move memory 4, scratchb, dmaaddr // save latest dmaddr
+data_mismatch_recover:
+ move memory 4, scratcha, state // save latest state
+ jump to_decisions // no need to save
+ // as interrupt routine
+ // did this
+data_in_normal:
+ move scratcha3 to sfbr
+ int error_too_much_data, if not 0
+ move from data_buf, when data_in
+data_in_mismatch:
+ move 2 to scratcha3
+ move memory 4, scratcha, state
+ call save_state
+ jump post_data_to_decisions
+data_out_phase:
+// int SIR_NOTIFY_DATA_OUT
+ move memory 4, state, scratcha
+ move memory 4, dmaaddr, scratchb
+data_out_block_loop:
+ move scratcha2 to sfbr
+ jump data_out_normal, if 0
+ move memory 4, dmaaddr, scratchb
+ move BSIZE, ptr dmaaddr, when data_out // transfer BSIZE bytes
+data_out_block_mismatch:
+ move scratchb1 + BSIZE / 256 to scratchb1 // add BSIZE to scratchb
+ move scratchb2 + 0 to scratchb2 with carry
+ move scratchb3 + 0 to scratchb3 with carry
+ move scratcha2 + 255 to scratcha2 // sub one from block count
+ move memory 4, scratchb, dmaaddr // save latest dmaddr
+ jump data_out_block_loop, when data_out
+ move memory 4, scratcha, state // save latest state
+ jump to_decisions
+data_out_normal:
+ move scratcha3 to sfbr
+ int error_too_little_data, if not 0
+ move from data_buf, when data_out
+data_out_mismatch:
+ move 2 to scratcha3
+ move memory 4, scratcha, state
+ call save_state
+ jump post_data_to_decisions
+status_phase:
+ move from status_buf, when status
+// int SIR_NOTIFY_STATUS
+ int error_unexpected_phase, when not msg_in
+msg_in_phase:
+ move 1, scratcha, when msg_in
+// int SIR_NOTIFY_MSG_IN
+ jump rejected, if MSG_REJECT
+msg_in_not_reject:
+ jump disconnected, if MSG_DISCONNECT
+ jump msg_in_skip, if MSG_SAVE_DATA_POINTER
+ jump msg_in_skip, if MSG_RESTORE_POINTERS
+ jump ignore_wide, if MSG_IGNORE_WIDE_RESIDUE
+ jump extended, if X_MSG
+ int error_not_cmd_complete, if not 0
+ move scntl2&0x7e to scntl2 // take care not to clear WSR
+ clear ack
+ wait disconnect
+ // update state
+ move memory 4, state, scratcha
+ move STATE_DONE to scratcha0
+ move RESULT_OK to scratcha1
+ move memory 4, scratcha, state
+ call save_state
+// int SIR_MSG_IO_COMPLETE
+ intfly 0
+ jump issue_check
+
+rejected:
+ int SIR_MSG_REJECT
+ clear ack
+ jump to_decisions
+msg_in_skip:
+ clear ack
+ jump to_decisions
+
+extended:
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha1, when msg_in
+ jump ext_3, if 3
+ jump ext_2, if 2
+ int error_weird_message, if not 1
+ext_1:
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha1, when msg_in
+ jump ext_done
+
+ext_3: clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha1, when msg_in
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha2, when msg_in
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha3, when msg_in
+ move scratcha1 to sfbr
+ jump ext_done, if not X_MSG_SDTR
+
+// the target sent SDTR - leave ACK asserted and signal kernel
+// kernel will either restart at reject, or continue
+sdtr: int SIR_MSG_SDTR
+ clear ack
+ jump to_decisions
+
+ext_2: clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha1, when msg_in
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha2, when msg_in
+ move scratcha1 to sfbr
+ jump ext_done, if not X_MSG_WDTR
+
+wdtr: int SIR_MSG_WDTR
+ clear ack
+ jump to_decisions
+
+ext_done:
+// ought to check message here, but instead reject all
+// NB ATN set
+reject:
+ set atn // get target's ATN
+ clear ack // finish ACK
+ move MSG_REJECT to scratcha // prepare message
+ int error_unexpected_phase, when not msg_out// didn't get ATN
+ clear atn // last byte coming
+ move 1, scratcha, when msg_out // send byte
+ clear ack // finish ACK
+ jump reject, when msg_out // parity error
+ jump to_decisions
+
+ignore_wide:
+ clear ack
+ int error_unexpected_phase, when not msg_in
+ move 1, scratcha1, when msg_in
+ int SIR_MSG_IGNORE_WIDE_RESIDUE
+ clear ack
+ jump to_decisions
+
+// sends a response to a message
+response:
+ set atn
+ clear ack
+ int error_unexpected_phase, when not msg_out
+response_repeat:
+ move from msg_out_buf, when msg_out
+ jump response_repeat, when msg_out // repeat on parity grounds
+// now look for response
+// msg_in could be a REJECT
+// anything other message is something else so signal kernel first
+ jump response_msg_in, when msg_in
+ int SIR_EV_RESPONSE_OK // not a MSG_IN so OK
+ jump to_decisions
+
+response_msg_in:
+ move 1, scratcha, when msg_in
+ jump rejected, if MSG_REJECT // go and generate rej interrupt
+ int SIR_EV_RESPONSE_OK // not a REJECT so OK
+ jump msg_in_not_reject // try others
+
+disconnected:
+// move 5 to ctest0
+ move scntl2&0x7e to scntl2 // don't clear WSR
+ clear ack
+ wait disconnect
+ // UPDATE state to disconnected
+ move memory 4, state, scratcha
+ move STATE_DISCONNECTED to scratcha0
+ move memory 4, scratcha, state
+ call save_state
+wsr_check:
+ move scntl2&0x01 to sfbr
+ int SIR_NOTIFY_WSR, if not 0
+// int SIR_NOTIFY_DISC
+ jump issue_check
+
+reselected_on_select:
+ int SIR_NOTIFY_RESELECTED_ON_SELECT
+ jump reselected
+
+wait_for_reselection:
+// move 11 to ctest0
+// int SIR_NOTIFY_WAIT_RESELECT
+ wait reselect sigp_set
+reselected:
+// move 12 to ctest0
+ clear target
+ int SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT, when not msg_in
+ move 1, scratchb, when msg_in
+ int error_not_identify_after_reselect, if not MSG_IDENTIFY and mask 0x1f
+// int SIR_NOTIFY_RESELECT
+ // now locate the right DSA - note do not clear ACK, so target doesn't start
+ // synchronous transfer until we are ready
+find_dsa:
+// move 6 to ctest0
+ move memory 4, dsa_head, dsa
+find_dsa_loop:
+// move 7 to ctest0
+ move dsa0 to sfbr
+ jump find_dsa_1, if not 0
+ move dsa1 to sfbr
+ jump find_dsa_1, if not 0
+ move dsa2 to sfbr
+ jump find_dsa_1, if not 0
+ move dsa3 to sfbr
+ int error_reselected, if 0 // couldn't match dsa (panic)
+find_dsa_1:
+// move 8 to ctest0
+ // load state from DSA into dsa_copy
+ call load_state
+ move memory 4, state, scratcha // get dsastate in scratcha
+ move scratcha0 to sfbr // and state variable in sfbr
+ jump find_dsa_next, if not STATE_DISCONNECTED // wrong state
+ move ssid & ssid_mask to sfbr // get target ID
+ move memory 1, targ, find_dsa_smc1 // forge target comparison instruction
+find_dsa_smc1:
+ jump find_dsa_next, if not 255 // jump if not matched
+ move memory 1, lun, find_dsa_smc2 // forge lun comparison instruction
+ move scratchb0 to sfbr // recover IDENTIFY message
+find_dsa_smc2:
+ jump reload_sync, if 255 and mask ~7 // off we jolly well go
+find_dsa_next:
+ move memory 4, next, dsa // find next
+ jump find_dsa_loop
+
+// id_out terminated early
+// most likely the message wasn't recognised
+// clear ATN and accept the message in
+id_out_mismatch_recover:
+ clear atn
+ jump msg_in_phase, when msg_in
+ int SIR_MSG_REJECT
+ jump to_decisions
+
+// Reload synchronous registers after a reconnect. If the transfer is a synchronous read, then
+// as soon as we clear ACK, the target will switch to data_in and start blasting data into the
+// fifo. We need to be executing the 'jump when data_in' instruction before the target stops REQing
+// since it is the REQ which latches the 'when'. The target will do 16 REQs before stopping, so
+// we have 16 bytes (160uS) plus delays to do this after clearing ACK. Once the jump is executing,
+// the target will wait, so as much debugging as you like can happen in data_in_phase, just don't
+// stick any delays between 'clear ack' and 'jump data_in_phase, when data_in'.
+
+reload_sync:
+ call load_sync
+ clear ack
+to_decisions:
+ jump data_in_phase, when data_in
+ jump cmd_phase, if cmd
+ jump data_out_phase, if data_out
+ jump status_phase, if status
+ jump msg_in_phase, if msg_in
+ int error_unexpected_phase
+post_data_to_decisions:
+ jump status_phase, when status
+ jump msg_in_phase, if msg_in
+ int error_unexpected_phase
+
+//
+// MULTI_TARGET
+//
+// following must mirror top of dsa structure
+// the first section is loaded and saved, the
+// second section loaded only
+dsa_copy:
+state: defw 0 // a0 is state, a1 result, a2 dma block count
+dmaaddr: defw 0 // dma address for block moves
+dsa_save_end:
+targ: defw 0 // lsb is target
+lun: defw 0 // lsb is lun
+sync: defw 0 // lsb is scntl3, sxfer
+next: defw 0
+dsa_load_end:
+dsa_load_len = dsa_load_end - dsa_copy
+dsa_save_len = dsa_save_end - dsa_copy
+
+load_state:
+ // load state from DSA into dsa_copy
+// move 9 to ctest0
+ move memory 4, dsa, load_state_smc0 + 4
+load_state_smc0:
+ move memory dsa_load_len, 0, dsa_copy
+// move 20 to ctest0
+ return
+save_state:
+ move memory 4, dsa, save_state_smc0 + 8
+save_state_smc0:
+ move memory dsa_save_len, dsa_copy, 0
+ return
+
+sigp_set:
+// int SIR_NOTIFY_SIGP
+ move ctest2 to sfbr // clear SIGP
+issue_check:
+// int SIR_NOTIFY_ISSUE_CHECK
+// move 1 to ctest0
+ move memory 4, dsa_head, dsa
+issue_check_loop:
+// move 2 to ctest0
+ move dsa0 to sfbr
+ jump issue_check_1, if not 0
+ move dsa1 to sfbr
+ jump issue_check_1, if not 0
+ move dsa2 to sfbr
+ jump issue_check_1, if not 0
+ move dsa3 to sfbr
+ jump wait_for_reselection, if 0 // nothing to do
+issue_check_1:
+// move 3 to ctest0
+ call load_state
+ move memory 4, state, scratcha // get dsastate in scratcha
+ move scratcha0 to sfbr // and state variable in sfbr
+ jump start, if STATE_ISSUE // right state
+issue_check_next:
+// move 4 to ctest0
+ move memory 4, next, dsa // find next
+ jump issue_check_loop
+load_sync:
+ move memory 4, sync, scratcha // load the sync stuff
+ move scratcha0 to sfbr // assuming load_state has been called
+ move sfbr to scntl3
+ move scratcha1 to sfbr
+ move sfbr to sxfer
+// int SIR_NOTIFY_LOAD_SYNC
+ return