RASCSI/cpp/controllers/abstract_controller.cpp

127 lines
2.8 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "shared/piscsi_exceptions.h"
#include "devices/primary_device.h"
#include "abstract_controller.h"
#include <ranges>
using namespace scsi_defs;
AbstractController::AbstractController(BUS& bus, int target_id, int max_luns) : bus(bus), target_id(target_id), max_luns(max_luns)
{
device_logger.SetIdAndLun(target_id, -1);
}
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<shared_ptr<PrimaryDevice>> AbstractController::GetDevices() const
{
unordered_set<shared_ptr<PrimaryDevice>> devices;
// "luns | views:values" is not supported by the bullseye compiler
ranges::transform(luns, inserter(devices, devices.begin()), [] (const auto& l) { return l.second; } );
return devices;
}
shared_ptr<PrimaryDevice> 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 = {};
SetByteTransfer(false);
// Reset all LUNs
for (const auto& [_, device] : luns) {
device->Reset();
}
GetBus().Reset();
}
void AbstractController::ProcessOnController(int id_data)
{
device_logger.SetIdAndLun(GetTargetId(), -1);
const int initiator_id = ExtractInitiatorId(id_data);
if (initiator_id != UNKNOWN_INITIATOR_ID) {
LogTrace("++++ Starting processing for initiator ID " + to_string(initiator_id));
}
else {
LogTrace("++++ Starting processing for unknown initiator ID");
}
while (Process(initiator_id)) {
// Handle bus phases until the bus is free for the next command
}
}
bool AbstractController::AddDevice(shared_ptr<PrimaryDevice> device)
{
const int lun = device->GetLun();
if (lun < 0 || lun >= GetMaxLuns() || HasDeviceForLun(lun) || device->GetController()) {
return false;
}
luns[lun] = device;
device->SetController(this);
return true;
}
bool AbstractController::RemoveDevice(PrimaryDevice& device)
{
device.CleanUp();
return luns.erase(device.GetLun()) == 1;
}
bool AbstractController::HasDeviceForLun(int lun) const
{
return luns.contains(lun);
}
int AbstractController::ExtractInitiatorId(int id_data) const
{
if (const int id_data_without_target = id_data - (1 << target_id); id_data_without_target) {
return static_cast<int>(log2(id_data_without_target & -id_data_without_target));
}
return UNKNOWN_INITIATOR_ID;
}