RASCSI/src/raspberrypi/controllers/abstract_controller.h
Uwe Seimet ddeede2beb
SASI code removal, error handling update, bug fixes, code cleanup (#806)
Summary ov most important changes triggered by the SASI code removal:

- Removed the SASI controller code
- New controller management. There is a new controller base class AbstractController and a class ControllerManager managing the controller lifecycle. The lifecycle management was removed from rasci.cpp and is covered by unit tests.
- New device management. The DeviceFactory manages the device lifecycle instead of rascsi.cpp. The new code is covered by unit tests.
- The lifecycle managment uses C++ collections with variable size instead of arrays with hard-coded sizes.
- The ScsiController method contains most of what was previously contained in scsidev_ctrl.cpp plus the code from sasidev_ctrl.cpp that was relevant for SCSI.
- scsi_command_util contains helper methods used for identical SCSI command implementations of more than one device
- Devices know their controllers, so that the controller instance does not need to be passed to each SCSI command. This change helps to decouple the devices from the controller. The phase_handler interface is also part of this decoupling.
- Use scsi_command_exception for propagating SCSI command execution errors, This resolves issues with the previous error handling, which was based on return values and often on magic numbers.
- Removed legacy SCSI error codes, all errors are now encoded by sense_key::, asc:: and status::.
- Fixed various warnings reported with -Wextra, -Weffc++ and -Wpedantic.
- Use constructor member initialization lists (recommended for ISO C++)
- Consistently use new/delete instead of malloc/free (recommended for ISO C++), resulting in better type safety and error handling
- Replaced variable sized arrays on the stack (violates ISO C++ and can cause a stack overflow)
- Replaced NULL by nullptr (recommended for C++), resulting in better type safety
- Use more const member functions in order to avoid side effects
- The format device page can now also be changed for hard disk drives (Fujitsu M2624S supports this, for instance), not just for MOs.
- Better encapsulation, updated access specifiers in many places
- Removed unused methods and method arguments
- Fixed a number of TODOs
- Added/updated unit tests for a lot of non-legacy classes
- Makefile support for creating HTML coverage reports with lcov/genhtml
2022-09-03 16:53:53 +02:00

98 lines
2.5 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
// Base class for device controllers
//
//---------------------------------------------------------------------------
#pragma once
#include "phase_handler.h"
#include <unordered_map>
using namespace std;
class PrimaryDevice;
class AbstractController : virtual public PhaseHandler
{
public:
// Maximum number of logical units
static const int LUN_MAX = 32;
enum rascsi_shutdown_mode {
NONE,
STOP_RASCSI,
STOP_PI,
RESTART_PI
};
// Internal data definition
// TODO Some of these data are probably device specific, and in this case they should be moved.
// These data are not internal, otherwise they could all be private
typedef struct _ctrl_t {
// General
BUS::phase_t phase = BUS::busfree; // Transition phase
// commands
DWORD cmd[16]; // Command data
DWORD status; // Status data
int message; // Message data
// Transfer
// TODO Try to get rid of the static buffer
BYTE *buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size
uint32_t blocks; // Number of transfer blocks
uint64_t next; // Next record
uint32_t offset; // Transfer offset
uint32_t length; // Transfer remaining length
// Logical units of this device controller mapped to their LUN numbers
unordered_map<int, PrimaryDevice *> luns;
} ctrl_t;
AbstractController(BUS *bus, int target_id) : bus(bus), target_id(target_id) {}
virtual ~AbstractController() {}
virtual BUS::phase_t Process(int) = 0;
virtual void Error(scsi_defs::sense_key, scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
scsi_defs::status = scsi_defs::status::CHECK_CONDITION) = 0;
virtual void Reset() = 0;
virtual int GetInitiatorId() const = 0;
virtual void SetByteTransfer(bool) = 0;
// Get requested LUN based on IDENTIFY message, with LUN from the CDB as fallback
virtual int GetEffectiveLun() const = 0;
virtual int GetMaxLuns() const = 0;
virtual void ScheduleShutdown(rascsi_shutdown_mode) = 0;
int GetTargetId() const { return target_id; }
PrimaryDevice *GetDeviceForLun(int) const;
bool AddDevice(PrimaryDevice *);
bool DeleteDevice(const PrimaryDevice *);
bool HasDeviceForLun(int) const;
int ExtractInitiatorId(int id_data);
// TODO Do not expose internal data
ctrl_t* GetCtrl() { return &ctrl; }
protected:
BUS *bus;
int target_id;
ctrl_t ctrl = {};
};