mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-26 09:29:28 +00:00
scsi_bus: various fixes and improvements.
This commit is contained in:
parent
9efac80271
commit
c51ea575ca
@ -45,13 +45,19 @@ enum {
|
|||||||
SCSI_CTRL_RST = 1 << 8,
|
SCSI_CTRL_RST = 1 << 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ScsiPhase : int {
|
namespace ScsiPhase {
|
||||||
|
enum : int {
|
||||||
BUS_FREE = 0,
|
BUS_FREE = 0,
|
||||||
ARBITRATION,
|
ARBITRATION,
|
||||||
SELECTION,
|
SELECTION,
|
||||||
RESELECTION,
|
RESELECTION,
|
||||||
|
COMMAND,
|
||||||
|
DATA,
|
||||||
|
STATUS,
|
||||||
|
MESSAGE,
|
||||||
RESET,
|
RESET,
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
enum ScsiMsg : int {
|
enum ScsiMsg : int {
|
||||||
CONFIRM_SEL = 1,
|
CONFIRM_SEL = 1,
|
||||||
@ -143,12 +149,18 @@ public:
|
|||||||
ScsiBus();
|
ScsiBus();
|
||||||
~ScsiBus() = default;
|
~ScsiBus() = default;
|
||||||
|
|
||||||
// low-level control/status
|
// low-level state management
|
||||||
void register_device(int id, ScsiDevice* dev_obj);
|
void register_device(int id, ScsiDevice* dev_obj);
|
||||||
|
int current_phase() { return this->cur_phase; };
|
||||||
|
|
||||||
|
// reading/writing control lines
|
||||||
void assert_ctrl_line(int id, uint16_t mask);
|
void assert_ctrl_line(int id, uint16_t mask);
|
||||||
void release_ctrl_line(int id, uint16_t mask);
|
void release_ctrl_line(int id, uint16_t mask);
|
||||||
void release_ctrl_lines(int id);
|
void release_ctrl_lines(int id);
|
||||||
int current_phase() { return this->cur_phase; };
|
uint16_t test_ctrl_lines(uint16_t mask);
|
||||||
|
|
||||||
|
// reading/writing data lines
|
||||||
|
uint8_t get_data_lines() { return this->data_lines; };
|
||||||
|
|
||||||
// high-level control/status
|
// high-level control/status
|
||||||
bool begin_arbitration(int id);
|
bool begin_arbitration(int id);
|
||||||
@ -156,6 +168,7 @@ public:
|
|||||||
bool begin_selection(int initiator_id, int target_id, bool atn);
|
bool begin_selection(int initiator_id, int target_id, bool atn);
|
||||||
void confirm_selection(int target_id);
|
void confirm_selection(int target_id);
|
||||||
bool end_selection(int initiator_id, int target_id);
|
bool end_selection(int initiator_id, int target_id);
|
||||||
|
bool transfer_command(uint8_t* dst_ptr);
|
||||||
void disconnect(int dev_id);
|
void disconnect(int dev_id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -98,6 +98,8 @@ void ScsiBus::release_ctrl_line(int id, uint16_t mask)
|
|||||||
this->cur_phase = ScsiPhase::BUS_FREE;
|
this->cur_phase = ScsiPhase::BUS_FREE;
|
||||||
change_bus_phase(id);
|
change_bus_phase(id);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this->ctrl_lines = new_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +108,18 @@ void ScsiBus::release_ctrl_lines(int id)
|
|||||||
this->release_ctrl_line(id, 0xFFFFUL);
|
this->release_ctrl_line(id, 0xFFFFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t ScsiBus::test_ctrl_lines(uint16_t mask)
|
||||||
|
{
|
||||||
|
uint16_t new_state = 0;
|
||||||
|
|
||||||
|
// OR control lines of all devices together
|
||||||
|
for (int i = 0; i < SCSI_MAX_DEVS; i++) {
|
||||||
|
new_state |= this->dev_ctrl_lines[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_state & mask;
|
||||||
|
}
|
||||||
|
|
||||||
bool ScsiBus::begin_arbitration(int initiator_id)
|
bool ScsiBus::begin_arbitration(int initiator_id)
|
||||||
{
|
{
|
||||||
if (this->cur_phase == ScsiPhase::BUS_FREE) {
|
if (this->cur_phase == ScsiPhase::BUS_FREE) {
|
||||||
@ -143,6 +157,8 @@ bool ScsiBus::begin_selection(int initiator_id, int target_id, bool atn)
|
|||||||
if (this->cur_phase != ScsiPhase::ARBITRATION || this->arb_winner_id != initiator_id)
|
if (this->cur_phase != ScsiPhase::ARBITRATION || this->arb_winner_id != initiator_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
this->assert_ctrl_line(initiator_id, SCSI_CTRL_SEL);
|
||||||
|
|
||||||
this->data_lines |= (1 << initiator_id) | (1 << target_id);
|
this->data_lines |= (1 << initiator_id) | (1 << target_id);
|
||||||
|
|
||||||
if (atn) {
|
if (atn) {
|
||||||
@ -171,6 +187,31 @@ bool ScsiBus::end_selection(int initiator_id, int target_id)
|
|||||||
return this->target_id == target_id;
|
return this->target_id == target_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// attempt to transfer the shortest Command Description Block (CDB)
|
||||||
|
if (!this->devices[this->initiator_id]->send_bytes(dst_ptr, 6)) {
|
||||||
|
LOG_F(ERROR, "ScsiBus: error while transferring CDB!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer the remaining CDB
|
||||||
|
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)) {
|
||||||
|
LOG_F(ERROR, "ScsiBus: error while transferring CDB!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ScsiBus::disconnect(int dev_id)
|
void ScsiBus::disconnect(int dev_id)
|
||||||
{
|
{
|
||||||
this->release_ctrl_lines(dev_id);
|
this->release_ctrl_lines(dev_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user