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