123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // 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
- SIR_NOTIFY_LOAD_STATE = 118
- STATE_FREE = 0
- STATE_ALLOCATED = 1
- STATE_ISSUE = 2
- STATE_DISCONNECTED = 3
- STATE_DONE = 4
- STATE_END = 5
- 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 // why is this here?
- 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 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
- int error_reselected, if STATE_END
- 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
- // called from sd53c8xx.c directly
- 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:
- // int SIR_NOTIFY_LOAD_STATE
- jump load_state_okay
- move dsa0 to sfbr
- jump load_state_okay, if not 0
- move dsa1 to sfbr
- jump load_state_okay, if not 0
- move dsa2 to sfbr
- jump load_state_okay, if not 0
- move dsa3 to sfbr
- jump load_state_okay, if not 0
- // dsa is 0
- move memory 4, dsa, dmaaddr
- move memory 4, dsa, targ
- move memory 4, dsa, lun
- move memory 4, dsa, sync
- move memory 4, dsa, next
- move memory 4, dsa, scratcha
- move STATE_END to sfbr
- move sfbr to scratcha0
- move memory 4, scratcha, state
- return
- load_state_okay:
- // 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:
- 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
- jump wait_for_reselection, if STATE_END
- // 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
|