plan9fox/sys/src/9/pc/sd53c8xx.n
2011-03-30 19:35:09 +03:00

460 lines
12 KiB
Plaintext

// 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