459 lines
12 KiB
Text
459 lines
12 KiB
Text
// 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
|