//--------------------------------------------------------------------------- // // SCSI Target Emulator RaSCSI Reloaded // for Raspberry Pi // // Copyright (C) 2022 Uwe Seimet // //--------------------------------------------------------------------------- #include "shared/rascsi_exceptions.h" #include "devices/primary_device.h" #include "abstract_controller.h" using namespace scsi_defs; void AbstractController::AllocateCmd(size_t size) { if (size > ctrl.cmd.size()) { ctrl.cmd.resize(size); } } void AbstractController::AllocateBuffer(size_t size) { if (size > ctrl.buffer.size()) { ctrl.buffer.resize(size); } } void AbstractController::SetByteTransfer(bool b) { is_byte_transfer = b; if (!is_byte_transfer) { bytes_to_transfer = 0; } } unordered_set> AbstractController::GetDevices() const { unordered_set> devices; for (const auto& [id, lun] : luns) { devices.insert(lun); } return devices; } shared_ptr AbstractController::GetDeviceForLun(int lun) const { const auto& it = luns.find(lun); return it == luns.end() ? nullptr : it->second; } void AbstractController::Reset() { SetPhase(phase_t::busfree); ctrl.status = status::GOOD; ctrl.message = 0x00; ctrl.blocks = 0; ctrl.next = 0; ctrl.offset = 0; ctrl.length = 0; // Reset all LUNs for (const auto& [lun, device] : luns) { device->Reset(); } } void AbstractController::ProcessPhase() { switch (GetPhase()) { case phase_t::busfree: BusFree(); break; case phase_t::selection: Selection(); break; case phase_t::dataout: DataOut(); break; case phase_t::datain: DataIn(); break; case phase_t::command: Command(); break; case phase_t::status: Status(); break; case phase_t::msgout: MsgOut(); break; case phase_t::msgin: MsgIn(); break; default: throw scsi_exception(sense_key::ABORTED_COMMAND); break; } } bool AbstractController::AddDevice(shared_ptr device) { if (device->GetLun() < 0 || device->GetLun() >= GetMaxLuns() || HasDeviceForLun(device->GetLun())) { return false; } luns[device->GetLun()] = device; device->SetController(shared_from_this()); return true; } bool AbstractController::RemoveDevice(shared_ptr device) { device->SetController(nullptr); return luns.erase(device->GetLun()) == 1; } bool AbstractController::HasDeviceForLun(int lun) const { return luns.find(lun) != luns.end(); } int AbstractController::ExtractInitiatorId(int id_data) const { int initiator_id = UNKNOWN_INITIATOR_ID; if (int tmp = id_data - (1 << target_id); tmp) { initiator_id = 0; for (int j = 0; j < 8; j++) { tmp >>= 1; if (tmp) { initiator_id++; } else { break; } } } return initiator_id; }