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