sc53c94: fix sending commands to SCSI devices.

This commit is contained in:
Maxim Poliakovski 2022-10-27 13:47:43 +02:00
parent 2065f3588b
commit f3cd5b8b36
4 changed files with 64 additions and 17 deletions

View File

@ -75,13 +75,14 @@ void Sc53C94::reset_device()
uint8_t Sc53C94::read(uint8_t reg_offset)
{
uint8_t int_status;
uint8_t status, int_status;
switch (reg_offset) {
case Read::Reg53C94::Command:
return this->cmd_fifo[0];
case Read::Reg53C94::Status:
return this->status;
status = bus_obj->test_ctrl_lines(SCSI_CTRL_MSG | SCSI_CTRL_CD | SCSI_CTRL_IO);
return (this->status & 0xF8) | status;
case Read::Reg53C94::Int_Status:
int_status = this->int_status;
this->seq_step = 0;
@ -92,6 +93,8 @@ uint8_t Sc53C94::read(uint8_t reg_offset)
return this->seq_step;
case Read::Reg53C94::FIFO_Flags:
return (this->seq_step << 5) | (this->data_fifo_pos & 0x1F);
case Read::Reg53C94::Config_1:
return this->config1;
case Read::Reg53C94::Config_3:
return this->config3;
case Read::Reg53C94::Xfer_Cnt_Hi:
@ -332,6 +335,12 @@ void Sc53C94::sequencer()
case SeqState::CMD_BEGIN:
LOG_F(INFO, "CMD_BEGIN reached");
break;
case SeqState::CMD_COMPLETE:
this->cmd_steps++;
this->int_status |= this->cmd_steps->status;
this->update_irq();
exec_next_command();
break;
default:
ABORT_F("SC53C94: unimplemented sequencer state %d", this->cur_state);
}
@ -350,16 +359,6 @@ void Sc53C94::update_irq()
void Sc53C94::notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param)
{
switch (msg_type) {
case ScsiMsg::BUS_PHASE_CHANGE:
switch (param) {
case ScsiPhase::COMMAND:
this->cur_state = SeqState::CMD_BEGIN;
this->sequencer();
break;
default:
LOG_F(WARNING, "SC53C94: ignore bus phase change %d message", param);
}
break;
case ScsiMsg::CONFIRM_SEL:
if (this->target_id == param) {
// cancel selection timeout timer
@ -370,6 +369,14 @@ void Sc53C94::notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param)
LOG_F(WARNING, "SC53C94: ignore invalid selection confirmation message");
}
break;
case ScsiMsg::SEND_CMD_BEGIN:
this->cur_state = SeqState::CMD_BEGIN;
this->sequencer();
break;
case ScsiMsg::SEND_CMD_END:
this->cur_state = SeqState::CMD_COMPLETE;
this->sequencer();
break;
default:
LOG_F(WARNING, "SC53C94: ignore notification message, type: %d", msg_type);
}

View File

@ -52,9 +52,11 @@ enum : int {
SELECTION,
RESELECTION,
COMMAND,
DATA,
DATA_IN,
DATA_OUT,
STATUS,
MESSAGE,
MESSAGE_IN,
MESSAGE_OUT,
RESET,
};
};
@ -62,6 +64,8 @@ enum : int {
enum ScsiMsg : int {
CONFIRM_SEL = 1,
BUS_PHASE_CHANGE,
SEND_CMD_BEGIN,
SEND_CMD_END,
};
enum ScsiCommand : int {
@ -165,6 +169,7 @@ public:
uint8_t get_data_lines() { return this->data_lines; };
// high-level control/status
int switch_phase(int id, int new_phase);
bool begin_arbitration(int id);
bool end_arbitration(int id);
bool begin_selection(int initiator_id, int target_id, bool atn);

View File

@ -120,6 +120,37 @@ uint16_t ScsiBus::test_ctrl_lines(uint16_t mask)
return new_state & mask;
}
int ScsiBus::switch_phase(int id, int new_phase)
{
int old_phase = this->cur_phase;
// leave the current phase (low-level)
switch (old_phase) {
case ScsiPhase::COMMAND:
this->release_ctrl_line(id, SCSI_CTRL_CD);
break;
case ScsiPhase::DATA_IN:
this->release_ctrl_line(id, SCSI_CTRL_IO);
break;
}
// enter new phase (low-level)
switch (new_phase) {
case ScsiPhase::COMMAND:
this->assert_ctrl_line(id, SCSI_CTRL_CD);
break;
case ScsiPhase::DATA_IN:
this->assert_ctrl_line(id, SCSI_CTRL_IO);
break;
}
// switch the bus to the new phase (high-level)
this->cur_phase = new_phase;
change_bus_phase(id);
return old_phase;
}
bool ScsiBus::begin_arbitration(int initiator_id)
{
if (this->cur_phase == ScsiPhase::BUS_FREE) {
@ -191,8 +222,9 @@ bool ScsiBus::transfer_command(uint8_t* dst_ptr)
{
static uint8_t cmd_to_cdb_length[8] = {6, 10, 10, 6, 6, 12, 6, 6};
this->cur_phase = ScsiPhase::COMMAND;
change_bus_phase(target_id);
this->switch_phase(target_id, ScsiPhase::COMMAND);
this->devices[this->initiator_id]->notify(this, ScsiMsg::SEND_CMD_BEGIN, 0);
// attempt to transfer the shortest Command Description Block (CDB)
if (!this->devices[this->initiator_id]->send_bytes(dst_ptr, 6)) {
@ -200,7 +232,7 @@ bool ScsiBus::transfer_command(uint8_t* dst_ptr)
return false;
}
// transfer the remaining CDB
// transfer the remaining CDB bytes if any
int cdb_length = cmd_to_cdb_length[dst_ptr[0] >> 5];
if (cdb_length > 6) {
if (!this->devices[this->initiator_id]->send_bytes(dst_ptr + 6, cdb_length - 6)) {
@ -209,6 +241,8 @@ bool ScsiBus::transfer_command(uint8_t* dst_ptr)
}
}
this->devices[this->initiator_id]->notify(this, ScsiMsg::SEND_CMD_END, 0);
return true;
}

View File

@ -49,6 +49,7 @@ void ScsiDevice::notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param)
}
bus_obj->transfer_command(this->cmd_buf);
//this->process_command();
bus_obj->switch_phase(this->scsi_id, ScsiPhase::DATA_IN);
});
}
break;