mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-25 20:33:35 +00:00
Updated memory management, added unit tests, fixed SonarCloud issues (#862)
* Updated memory management. Final goal is to get rid of raw pointers everywhere. * Added unit tests * Fixed SonarCloud issues
This commit is contained in:
parent
78bab77f4b
commit
255a6e139f
@ -16,12 +16,12 @@ class Localizer;
|
||||
|
||||
struct CommandContext
|
||||
{
|
||||
CommandContext(SocketConnector *c, const Localizer *l, int f, const std::string& s)
|
||||
CommandContext(const SocketConnector& c, const Localizer& l, int f, const std::string& s)
|
||||
: connector(c), localizer(l), fd(f), locale(s) {}
|
||||
~CommandContext() = default;
|
||||
|
||||
SocketConnector *connector;
|
||||
const Localizer *localizer;
|
||||
const SocketConnector& connector;
|
||||
const Localizer& localizer;
|
||||
int fd;
|
||||
std::string locale;
|
||||
};
|
||||
|
@ -28,26 +28,27 @@ void command_util::ParseParameters(PbDeviceDefinition& device, const string& par
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.find(KEY_VALUE_SEPARATOR) != string::npos) {
|
||||
stringstream ss(params);
|
||||
string p;
|
||||
while (getline(ss, p, COMPONENT_SEPARATOR)) {
|
||||
if (!p.empty()) {
|
||||
size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
|
||||
if (separator_pos != string::npos) {
|
||||
AddParam(device, p.substr(0, separator_pos), string_view(p).substr(separator_pos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Old style parameters, for backwards compatibility only.
|
||||
// Only one of these parameters will be used by rascsi, depending on the device type.
|
||||
else {
|
||||
if (params.find(KEY_VALUE_SEPARATOR) == string::npos) {
|
||||
AddParam(device, "file", params);
|
||||
if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") {
|
||||
AddParam(device, "interfaces", params);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stringstream ss(params);
|
||||
string p;
|
||||
while (getline(ss, p, COMPONENT_SEPARATOR)) {
|
||||
if (!p.empty()) {
|
||||
size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
|
||||
if (separator_pos != string::npos) {
|
||||
AddParam(device, p.substr(0, separator_pos), string_view(p).substr(separator_pos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string command_util::GetParam(const PbCommand& command, const string& key)
|
||||
@ -86,24 +87,24 @@ void command_util::AddParam(PbDeviceDefinition& device, const string& key, strin
|
||||
}
|
||||
}
|
||||
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
|
||||
const string& arg1, const string& arg2, const string& arg3)
|
||||
{
|
||||
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
|
||||
const PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
|
||||
PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
|
||||
{
|
||||
// For the logfile always use English
|
||||
LOGERROR("%s", context.localizer->Localize(key, "en", arg1, arg2, arg3).c_str())
|
||||
LOGERROR("%s", context.localizer.Localize(key, "en", arg1, arg2, arg3).c_str())
|
||||
|
||||
return ReturnStatus(context, false, context.localizer->Localize(key, context.locale, arg1, arg2, arg3), error_code,
|
||||
return ReturnStatus(context, false, context.localizer.Localize(key, context.locale, arg1, arg2, arg3), error_code,
|
||||
false);
|
||||
}
|
||||
|
||||
bool command_util::ReturnStatus(const CommandContext& context, bool status, const string& msg,
|
||||
const PbErrorCode error_code, bool log)
|
||||
PbErrorCode error_code, bool log)
|
||||
{
|
||||
// Do not log twice if logging has already been done in the localized error handling above
|
||||
if (log && !status && !msg.empty()) {
|
||||
@ -128,7 +129,7 @@ bool command_util::ReturnStatus(const CommandContext& context, bool status, cons
|
||||
result.set_status(status);
|
||||
result.set_error_code(error_code);
|
||||
result.set_msg(msg);
|
||||
context.connector->SerializeMessage(context.fd, result);
|
||||
context.connector.SerializeMessage(context.fd, result);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -27,10 +27,10 @@ namespace command_util
|
||||
void AddParam(PbCommand&, const string&, string_view);
|
||||
void AddParam(PbDevice&, const string&, string_view);
|
||||
void AddParam(PbDeviceDefinition&, const string&, string_view);
|
||||
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const string& = "", const string& = "",
|
||||
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, const string& = "", const string& = "",
|
||||
const string& = "");
|
||||
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "",
|
||||
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, PbErrorCode, const string& = "",
|
||||
const string& = "", const string& = "");
|
||||
bool ReturnStatus(const CommandContext&, bool = true, const string& = "",
|
||||
const PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
|
||||
PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
|
||||
}
|
||||
|
@ -10,9 +10,74 @@
|
||||
#include "abstract_controller.h"
|
||||
#include "devices/primary_device.h"
|
||||
|
||||
void AbstractController::AllocateBuffer(size_t size)
|
||||
{
|
||||
if (size > ctrl.buffer.size()) {
|
||||
ctrl.buffer.resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryDevice *AbstractController::GetDeviceForLun(int lun) const {
|
||||
const auto& it = ctrl.luns.find(lun);
|
||||
return it == ctrl.luns.end() ? nullptr : it->second;
|
||||
const auto& it = luns.find(lun);
|
||||
return it == luns.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
void AbstractController::Reset()
|
||||
{
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
|
||||
ctrl.status = 0x00;
|
||||
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 BUS::phase_t::busfree:
|
||||
BusFree();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::selection:
|
||||
Selection();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
DataOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::datain:
|
||||
DataIn();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::command:
|
||||
Command();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::status:
|
||||
Status();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
MsgOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgin:
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractController::AddDevice(PrimaryDevice *device)
|
||||
@ -25,7 +90,7 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.luns[device->GetLun()] = device;
|
||||
luns[device->GetLun()] = device;
|
||||
device->SetController(this);
|
||||
|
||||
return true;
|
||||
@ -33,12 +98,12 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
|
||||
|
||||
bool AbstractController::DeleteDevice(const PrimaryDevice *device)
|
||||
{
|
||||
return ctrl.luns.erase(device->GetLun()) == 1;
|
||||
return luns.erase(device->GetLun()) == 1;
|
||||
}
|
||||
|
||||
bool AbstractController::HasDeviceForLun(int lun) const
|
||||
{
|
||||
return ctrl.luns.find(lun) != ctrl.luns.end();
|
||||
return luns.find(lun) != luns.end();
|
||||
}
|
||||
|
||||
int AbstractController::ExtractInitiatorId(int id_data) const
|
||||
|
@ -16,14 +16,21 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
class PrimaryDevice;
|
||||
|
||||
class AbstractController
|
||||
{
|
||||
public:
|
||||
friend class PrimaryDevice;
|
||||
friend class ScsiController;
|
||||
|
||||
// Maximum number of logical units
|
||||
static const int LUN_MAX = 32;
|
||||
BUS::phase_t phase = BUS::phase_t::busfree;
|
||||
|
||||
// Logical units of this device controller mapped to their LUN numbers
|
||||
unordered_map<int, PrimaryDevice *> luns;
|
||||
|
||||
public:
|
||||
|
||||
enum class rascsi_shutdown_mode {
|
||||
NONE,
|
||||
@ -33,32 +40,23 @@ public:
|
||||
};
|
||||
|
||||
using ctrl_t = struct _ctrl_t {
|
||||
// General
|
||||
BUS::phase_t phase = BUS::phase_t::busfree; // Transition phase
|
||||
|
||||
// commands
|
||||
std::vector<int> cmd; // Command data, dynamically allocated per received command
|
||||
vector<int> cmd; // Command data, dynamically allocated per received command
|
||||
uint32_t status; // Status data
|
||||
int message; // Message data
|
||||
|
||||
// Transfer
|
||||
BYTE *buffer; // Transfer data buffer
|
||||
int bufsize; // Transfer data buffer size
|
||||
vector<BYTE> buffer; // Transfer data buffer
|
||||
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
|
||||
std::unordered_map<int, PrimaryDevice *> luns;
|
||||
};
|
||||
|
||||
AbstractController(shared_ptr<BUS> bus, int target_id) : target_id(target_id), bus(bus) {}
|
||||
AbstractController(shared_ptr<BUS> bus, int target_id, int luns) : target_id(target_id), bus(bus), max_luns(luns) {}
|
||||
virtual ~AbstractController() = default;
|
||||
AbstractController(AbstractController&) = delete;
|
||||
AbstractController& operator=(const AbstractController&) = delete;
|
||||
|
||||
virtual void SetPhase(BUS::phase_t) = 0;
|
||||
virtual void BusFree() = 0;
|
||||
virtual void Selection() = 0;
|
||||
virtual void Command() = 0;
|
||||
@ -72,18 +70,18 @@ public:
|
||||
|
||||
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 void Reset();
|
||||
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; }
|
||||
int GetMaxLuns() const { return max_luns; }
|
||||
bool HasLuns() const { return !luns.empty(); }
|
||||
|
||||
PrimaryDevice *GetDeviceForLun(int) const;
|
||||
bool AddDevice(PrimaryDevice *);
|
||||
@ -91,17 +89,46 @@ public:
|
||||
bool HasDeviceForLun(int) const;
|
||||
int ExtractInitiatorId(int id_data) const;
|
||||
|
||||
// TODO Do not expose internal data
|
||||
ctrl_t* GetCtrl() { return &ctrl; }
|
||||
|
||||
int target_id;
|
||||
void AllocateBuffer(size_t);
|
||||
vector<BYTE>& GetBuffer() { return ctrl.buffer; }
|
||||
size_t GetBufferSize() const { return ctrl.buffer.size(); }
|
||||
uint32_t GetStatus() const { return ctrl.status; }
|
||||
void SetStatus(uint32_t s) { ctrl.status = s; }
|
||||
uint32_t GetLength() const { return ctrl.length; }
|
||||
|
||||
protected:
|
||||
|
||||
scsi_defs::scsi_command GetOpcode() const { return (scsi_defs::scsi_command)ctrl.cmd[0]; }
|
||||
int GetLun() const { return (ctrl.cmd[1] >> 5) & 0x07; }
|
||||
|
||||
void ProcessPhase();
|
||||
|
||||
vector<int>& InitCmd(int size) { ctrl.cmd.resize(size); return ctrl.cmd; }
|
||||
|
||||
bool HasValidLength() const { return ctrl.length != 0; }
|
||||
void ResetOffset() { ctrl.offset = 0; }
|
||||
void UpdateOffsetAndLength() { ctrl.offset += ctrl.length; ctrl.length = 0; }
|
||||
|
||||
BUS::phase_t GetPhase() const { return phase; }
|
||||
void SetPhase(BUS::phase_t p) { phase = p; }
|
||||
bool IsSelection() const { return phase == BUS::phase_t::selection; }
|
||||
bool IsBusFree() const { return phase == BUS::phase_t::busfree; }
|
||||
bool IsCommand() const { return phase == BUS::phase_t::command; }
|
||||
bool IsStatus() const { return phase == BUS::phase_t::status; }
|
||||
bool IsDataIn() const { return phase == BUS::phase_t::datain; }
|
||||
bool IsDataOut() const { return phase == BUS::phase_t::dataout; }
|
||||
bool IsMsgIn() const { return phase == BUS::phase_t::msgin; }
|
||||
bool IsMsgOut() const { return phase == BUS::phase_t::msgout; }
|
||||
|
||||
private:
|
||||
|
||||
int target_id;
|
||||
|
||||
shared_ptr<BUS> bus;
|
||||
|
||||
int max_luns;
|
||||
|
||||
ctrl_t ctrl = {};
|
||||
|
||||
ctrl_t* GetCtrl() { return &ctrl; }
|
||||
};
|
||||
|
@ -10,8 +10,6 @@
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI device controller ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "log.h"
|
||||
@ -29,42 +27,26 @@
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
ScsiController::ScsiController(shared_ptr<BUS> bus, int target_id) : AbstractController(bus, target_id)
|
||||
ScsiController::ScsiController(shared_ptr<BUS> bus, int target_id) : AbstractController(bus, target_id, LUN_MAX)
|
||||
{
|
||||
// The initial buffer size will default to either the default buffer size OR
|
||||
// the size of an Ethernet message, whichever is larger.
|
||||
ctrl.bufsize = std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN);
|
||||
ctrl.buffer = new BYTE[ctrl.bufsize];
|
||||
}
|
||||
|
||||
ScsiController::~ScsiController()
|
||||
{
|
||||
delete[] ctrl.buffer;
|
||||
AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN));
|
||||
}
|
||||
|
||||
void ScsiController::Reset()
|
||||
{
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
ctrl.status = 0x00;
|
||||
ctrl.message = 0x00;
|
||||
AbstractController::Reset();
|
||||
|
||||
execstart = 0;
|
||||
ctrl.blocks = 0;
|
||||
ctrl.next = 0;
|
||||
ctrl.offset = 0;
|
||||
ctrl.length = 0;
|
||||
identified_lun = -1;
|
||||
|
||||
scsi.atnmsg = false;
|
||||
scsi.msc = 0;
|
||||
memset(scsi.msb.data(), 0x00, scsi.msb.size());
|
||||
scsi.msb = {};
|
||||
|
||||
is_byte_transfer = false;
|
||||
bytes_to_transfer = 0;
|
||||
|
||||
// Reset all LUNs
|
||||
for (const auto& [lun, device] : ctrl.luns) {
|
||||
device->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
BUS::phase_t ScsiController::Process(int id)
|
||||
@ -82,7 +64,7 @@ BUS::phase_t ScsiController::Process(int id)
|
||||
// Reset the bus
|
||||
bus->Reset();
|
||||
|
||||
return ctrl.phase;
|
||||
return GetPhase();
|
||||
}
|
||||
|
||||
if (id != UNKNOWN_INITIATOR_ID) {
|
||||
@ -95,44 +77,7 @@ BUS::phase_t ScsiController::Process(int id)
|
||||
initiator_id = id;
|
||||
|
||||
try {
|
||||
// Phase processing
|
||||
switch (ctrl.phase) {
|
||||
case BUS::phase_t::busfree:
|
||||
BusFree();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::selection:
|
||||
Selection();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
DataOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::datain:
|
||||
DataIn();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::command:
|
||||
Command();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::status:
|
||||
Status();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
MsgOut();
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgin:
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
ProcessPhase();
|
||||
}
|
||||
catch(const scsi_error_exception&) {
|
||||
// Any exception should have been handled during the phase processing
|
||||
@ -146,12 +91,12 @@ BUS::phase_t ScsiController::Process(int id)
|
||||
BusFree();
|
||||
}
|
||||
|
||||
return ctrl.phase;
|
||||
return GetPhase();
|
||||
}
|
||||
|
||||
void ScsiController::BusFree()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::busfree) {
|
||||
if (!IsBusFree()) {
|
||||
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::phase_t::busfree);
|
||||
@ -163,7 +108,7 @@ void ScsiController::BusFree()
|
||||
bus->SetBSY(false);
|
||||
|
||||
// Initialize status and message
|
||||
ctrl.status = 0x00;
|
||||
SetStatus(0);
|
||||
ctrl.message = 0x00;
|
||||
|
||||
// Initialize ATN message reception status
|
||||
@ -211,14 +156,14 @@ void ScsiController::BusFree()
|
||||
|
||||
void ScsiController::Selection()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::selection) {
|
||||
if (!IsSelection()) {
|
||||
// A different device controller was selected
|
||||
if (int id = 1 << GetTargetId(); ((int)bus->GetDAT() & id) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Abort if there is no LUN for this controller
|
||||
if (ctrl.luns.empty()) {
|
||||
if (!HasLuns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -244,7 +189,7 @@ void ScsiController::Selection()
|
||||
|
||||
void ScsiController::Command()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::command) {
|
||||
if (!IsCommand()) {
|
||||
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::phase_t::command);
|
||||
@ -253,8 +198,8 @@ void ScsiController::Command()
|
||||
bus->SetCD(true);
|
||||
bus->SetIO(false);
|
||||
|
||||
int actual_count = bus->CommandHandShake(ctrl.buffer);
|
||||
int command_byte_count = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
int actual_count = bus->CommandHandShake(GetBuffer().data());
|
||||
int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
|
||||
|
||||
// If not able to receive all, move to the status phase
|
||||
if (actual_count != command_byte_count) {
|
||||
@ -264,12 +209,12 @@ void ScsiController::Command()
|
||||
return;
|
||||
}
|
||||
|
||||
ctrl.cmd.resize(command_byte_count);
|
||||
InitCmd(command_byte_count);
|
||||
|
||||
// Command data transfer
|
||||
stringstream s;
|
||||
for (int i = 0; i < command_byte_count; i++) {
|
||||
ctrl.cmd[i] = ctrl.buffer[i];
|
||||
ctrl.cmd[i] = GetBuffer()[i];
|
||||
s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
|
||||
}
|
||||
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
|
||||
@ -287,13 +232,13 @@ void ScsiController::Execute()
|
||||
SetPhase(BUS::phase_t::execute);
|
||||
|
||||
// Initialization for data transfer
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
ctrl.blocks = 1;
|
||||
execstart = SysTimer::GetTimerLow();
|
||||
|
||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||
if (GetOpcode() != scsi_command::eCmdRequestSense) {
|
||||
ctrl.status = 0;
|
||||
SetStatus(0);
|
||||
}
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
@ -339,13 +284,13 @@ void ScsiController::Execute()
|
||||
|
||||
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, device->GetId())
|
||||
|
||||
ctrl.buffer[0] = 0x7f;
|
||||
GetBuffer().data()[0] = 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
void ScsiController::Status()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::status) {
|
||||
if (!IsStatus()) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
@ -353,7 +298,7 @@ void ScsiController::Status()
|
||||
SysTimer::SleepUsec(5);
|
||||
}
|
||||
|
||||
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, ctrl.status)
|
||||
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, GetStatus())
|
||||
|
||||
SetPhase(BUS::phase_t::status);
|
||||
|
||||
@ -363,10 +308,10 @@ void ScsiController::Status()
|
||||
bus->SetIO(true);
|
||||
|
||||
// Data transfer is 1 byte x 1 block
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
ctrl.buffer[0] = (BYTE)ctrl.status;
|
||||
GetBuffer()[0] = (BYTE)GetStatus();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -376,7 +321,7 @@ void ScsiController::Status()
|
||||
|
||||
void ScsiController::MsgIn()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::msgin) {
|
||||
if (!IsMsgIn()) {
|
||||
LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__)
|
||||
|
||||
SetPhase(BUS::phase_t::msgin);
|
||||
@ -386,9 +331,9 @@ void ScsiController::MsgIn()
|
||||
bus->SetIO(true);
|
||||
|
||||
// length, blocks are already set
|
||||
assert(ctrl.length > 0);
|
||||
assert(HasValidLength());
|
||||
assert(ctrl.blocks > 0);
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -400,14 +345,14 @@ void ScsiController::MsgOut()
|
||||
{
|
||||
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId())
|
||||
|
||||
if (ctrl.phase != BUS::phase_t::msgout) {
|
||||
if (!IsMsgOut()) {
|
||||
LOGTRACE("Message Out Phase")
|
||||
|
||||
// process the IDENTIFY message
|
||||
if (ctrl.phase == BUS::phase_t::selection) {
|
||||
if (IsSelection()) {
|
||||
scsi.atnmsg = true;
|
||||
scsi.msc = 0;
|
||||
memset(scsi.msb.data(), 0x00, scsi.msb.size());
|
||||
scsi.msb = {};
|
||||
}
|
||||
|
||||
SetPhase(BUS::phase_t::msgout);
|
||||
@ -417,7 +362,7 @@ void ScsiController::MsgOut()
|
||||
bus->SetIO(false);
|
||||
|
||||
// Data transfer is 1 byte x 1 block
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
|
||||
@ -429,14 +374,14 @@ void ScsiController::MsgOut()
|
||||
|
||||
void ScsiController::DataIn()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::datain) {
|
||||
if (!IsDataIn()) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
}
|
||||
|
||||
// If the length is 0, go to the status phase
|
||||
if (ctrl.length == 0) {
|
||||
if (!HasValidLength()) {
|
||||
Status();
|
||||
return;
|
||||
}
|
||||
@ -451,7 +396,7 @@ void ScsiController::DataIn()
|
||||
|
||||
// length, blocks are already set
|
||||
assert(ctrl.blocks > 0);
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -461,14 +406,14 @@ void ScsiController::DataIn()
|
||||
|
||||
void ScsiController::DataOut()
|
||||
{
|
||||
if (ctrl.phase != BUS::phase_t::dataout) {
|
||||
if (!IsDataOut()) {
|
||||
// Minimum execution time
|
||||
if (execstart > 0) {
|
||||
Sleep();
|
||||
}
|
||||
|
||||
// If the length is 0, go to the status phase
|
||||
if (ctrl.length == 0) {
|
||||
if (!HasValidLength()) {
|
||||
Status();
|
||||
return;
|
||||
}
|
||||
@ -482,7 +427,7 @@ void ScsiController::DataOut()
|
||||
bus->SetCD(false);
|
||||
bus->SetIO(false);
|
||||
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -503,7 +448,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
|
||||
}
|
||||
|
||||
// Bus free for status phase and message in phase
|
||||
if (ctrl.phase == BUS::phase_t::status || ctrl.phase == BUS::phase_t::msgin) {
|
||||
if (IsStatus() || IsMsgIn()) {
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
@ -520,7 +465,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
|
||||
GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
|
||||
}
|
||||
|
||||
ctrl.status = (uint32_t)status;
|
||||
SetStatus((uint32_t)status);
|
||||
ctrl.message = 0x00;
|
||||
|
||||
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__)
|
||||
@ -533,13 +478,13 @@ void ScsiController::Send()
|
||||
assert(!bus->GetREQ());
|
||||
assert(bus->GetIO());
|
||||
|
||||
if (ctrl.length != 0) {
|
||||
if (HasValidLength()) {
|
||||
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(ctrl.offset) + ", length "
|
||||
+ to_string(ctrl.length)).c_str())
|
||||
|
||||
// TODO The delay has to be taken from ctrl.unit[lun], but as there are currently no Daynaport drivers for
|
||||
// LUNs other than 0 this work-around works.
|
||||
if (int len = bus->SendHandShake(&ctrl.buffer[ctrl.offset], ctrl.length,
|
||||
if (int len = bus->SendHandShake(GetBuffer().data() + ctrl.offset, ctrl.length,
|
||||
HasDeviceForLun(0) ? GetDeviceForLun(0)->GetSendDelay() : 0);
|
||||
len != (int)ctrl.length) {
|
||||
// If you cannot send all, move to status phase
|
||||
@ -547,9 +492,8 @@ void ScsiController::Send()
|
||||
return;
|
||||
}
|
||||
|
||||
// offset and length
|
||||
ctrl.offset += ctrl.length;
|
||||
ctrl.length = 0;
|
||||
UpdateOffsetAndLength();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -558,9 +502,9 @@ void ScsiController::Send()
|
||||
bool result = true;
|
||||
|
||||
// Processing after data collection (read/data-in only)
|
||||
if (ctrl.phase == BUS::phase_t::datain && ctrl.blocks != 0) {
|
||||
if (IsDataIn() && ctrl.blocks != 0) {
|
||||
// set next buffer (set offset, length)
|
||||
result = XferIn(ctrl.buffer);
|
||||
result = XferIn(GetBuffer());
|
||||
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Processing after data collection. Blocks: " + to_string(ctrl.blocks)).c_str())
|
||||
}
|
||||
|
||||
@ -573,14 +517,14 @@ void ScsiController::Send()
|
||||
// Continue sending if block !=0
|
||||
if (ctrl.blocks != 0){
|
||||
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Continuing to send. Blocks: " + to_string(ctrl.blocks)).c_str())
|
||||
assert(ctrl.length > 0);
|
||||
assert(HasValidLength());
|
||||
assert(ctrl.offset == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to next phase
|
||||
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), (int)ctrl.phase)
|
||||
switch (ctrl.phase) {
|
||||
LOGTRACE("%s Move to next phase: %s", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
|
||||
switch (GetPhase()) {
|
||||
// Message in phase
|
||||
case BUS::phase_t::msgin:
|
||||
// Completed sending response to extended message of IDENTIFY message
|
||||
@ -607,7 +551,7 @@ void ScsiController::Send()
|
||||
// Message in phase
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
ctrl.buffer[0] = (BYTE)ctrl.message;
|
||||
GetBuffer()[0] = (BYTE)ctrl.message;
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
@ -631,20 +575,19 @@ void ScsiController::Receive()
|
||||
assert(!bus->GetIO());
|
||||
|
||||
// Length != 0 if received
|
||||
if (ctrl.length != 0) {
|
||||
if (HasValidLength()) {
|
||||
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
|
||||
|
||||
// If not able to receive all, move to status phase
|
||||
if (int len = bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
|
||||
if (int len = bus->ReceiveHandShake(GetBuffer().data() + ctrl.offset, ctrl.length);
|
||||
len != (int)ctrl.length) {
|
||||
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, ctrl.length, len)
|
||||
Error(sense_key::ABORTED_COMMAND);
|
||||
return;
|
||||
}
|
||||
|
||||
// Offset and Length
|
||||
ctrl.offset += ctrl.length;
|
||||
ctrl.length = 0;
|
||||
UpdateOffsetAndLength();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -653,8 +596,8 @@ void ScsiController::Receive()
|
||||
bool result = true;
|
||||
|
||||
// Processing after receiving data (by phase)
|
||||
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
|
||||
switch (ctrl.phase) {
|
||||
LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::dataout:
|
||||
if (ctrl.blocks == 0) {
|
||||
// End with this buffer
|
||||
@ -666,7 +609,7 @@ void ScsiController::Receive()
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
ctrl.message = ctrl.buffer[0];
|
||||
ctrl.message = GetBuffer()[0];
|
||||
if (!XferMsg(ctrl.message)) {
|
||||
// Immediately free the bus if message output fails
|
||||
BusFree();
|
||||
@ -689,13 +632,13 @@ void ScsiController::Receive()
|
||||
|
||||
// Continue to receive if block !=0
|
||||
if (ctrl.blocks != 0) {
|
||||
assert(ctrl.length > 0);
|
||||
assert(HasValidLength());
|
||||
assert(ctrl.offset == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to next phase
|
||||
switch (ctrl.phase) {
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::command:
|
||||
ProcessCommand();
|
||||
break;
|
||||
@ -718,7 +661,7 @@ void ScsiController::Receive()
|
||||
|
||||
bool ScsiController::XferMsg(int msg)
|
||||
{
|
||||
assert(ctrl.phase == BUS::phase_t::msgout);
|
||||
assert(IsMsgOut());
|
||||
|
||||
// Save message out data
|
||||
if (scsi.atnmsg) {
|
||||
@ -732,17 +675,14 @@ bool ScsiController::XferMsg(int msg)
|
||||
|
||||
void ScsiController::ReceiveBytes()
|
||||
{
|
||||
LOGTRACE("%s",__PRETTY_FUNCTION__)
|
||||
|
||||
// REQ is low
|
||||
assert(!bus->GetREQ());
|
||||
assert(!bus->GetIO());
|
||||
|
||||
if (ctrl.length) {
|
||||
if (HasValidLength()) {
|
||||
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
|
||||
|
||||
// If not able to receive all, move to status phase
|
||||
if (uint32_t len = bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
|
||||
if (uint32_t len = bus->ReceiveHandShake(GetBuffer().data() + ctrl.offset, ctrl.length);
|
||||
len != ctrl.length) {
|
||||
LOGERROR("%s Not able to receive %d bytes of data, only received %d",
|
||||
__PRETTY_FUNCTION__, ctrl.length, len)
|
||||
@ -752,8 +692,7 @@ void ScsiController::ReceiveBytes()
|
||||
|
||||
bytes_to_transfer = ctrl.length;
|
||||
|
||||
ctrl.offset += ctrl.length;
|
||||
ctrl.length = 0;
|
||||
UpdateOffsetAndLength();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -762,15 +701,14 @@ void ScsiController::ReceiveBytes()
|
||||
bool result = true;
|
||||
|
||||
// Processing after receiving data (by phase)
|
||||
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
|
||||
switch (ctrl.phase) {
|
||||
|
||||
LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::dataout:
|
||||
result = XferOut(false);
|
||||
break;
|
||||
|
||||
case BUS::phase_t::msgout:
|
||||
ctrl.message = ctrl.buffer[0];
|
||||
ctrl.message = GetBuffer()[0];
|
||||
if (!XferMsg(ctrl.message)) {
|
||||
// Immediately free the bus if message output fails
|
||||
BusFree();
|
||||
@ -792,7 +730,7 @@ void ScsiController::ReceiveBytes()
|
||||
}
|
||||
|
||||
// Move to next phase
|
||||
switch (ctrl.phase) {
|
||||
switch (GetPhase()) {
|
||||
case BUS::phase_t::command:
|
||||
ProcessCommand();
|
||||
break;
|
||||
@ -813,7 +751,7 @@ void ScsiController::ReceiveBytes()
|
||||
|
||||
bool ScsiController::XferOut(bool cont)
|
||||
{
|
||||
assert(ctrl.phase == BUS::phase_t::dataout);
|
||||
assert(IsDataOut());
|
||||
|
||||
if (!is_byte_transfer) {
|
||||
return XferOutBlockOriented(cont);
|
||||
@ -823,17 +761,17 @@ bool ScsiController::XferOut(bool cont)
|
||||
|
||||
if (auto device = GetDeviceForLun(GetEffectiveLun());
|
||||
device != nullptr && GetOpcode() == scsi_command::eCmdWrite6) {
|
||||
return device->WriteByteSequence(ctrl.buffer, bytes_to_transfer);
|
||||
return device->WriteByteSequence(GetBuffer(), bytes_to_transfer);
|
||||
}
|
||||
|
||||
LOGWARN("Received an unexpected command ($%02X) in %s", (int)GetOpcode(), __PRETTY_FUNCTION__)
|
||||
LOGWARN("%s Received unexpected command $%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScsiController::FlushUnit()
|
||||
{
|
||||
assert(ctrl.phase == BUS::phase_t::dataout);
|
||||
assert(IsDataOut());
|
||||
|
||||
auto disk = dynamic_cast<Disk *>(GetDeviceForLun(GetEffectiveLun()));
|
||||
if (disk == nullptr) {
|
||||
@ -857,7 +795,7 @@ void ScsiController::FlushUnit()
|
||||
// Without it we would not need this method at all.
|
||||
// ModeSelect is already handled in XferOutBlockOriented(). Why would it have to be handled once more?
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
|
||||
disk->ModeSelect(ctrl.cmd, GetBuffer(), ctrl.offset);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
|
||||
@ -882,9 +820,9 @@ void ScsiController::FlushUnit()
|
||||
// *Reset offset and length
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool ScsiController::XferIn(BYTE *buf)
|
||||
bool ScsiController::XferIn(vector<BYTE>& buf)
|
||||
{
|
||||
assert(ctrl.phase == BUS::phase_t::datain);
|
||||
assert(IsDataIn());
|
||||
|
||||
LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
|
||||
|
||||
@ -910,7 +848,7 @@ bool ScsiController::XferIn(BYTE *buf)
|
||||
ctrl.next++;
|
||||
|
||||
// If things are normal, work setting
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
break;
|
||||
|
||||
// Other (impossible)
|
||||
@ -940,7 +878,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
case scsi_command::eCmdModeSelect6:
|
||||
case scsi_command::eCmdModeSelect10:
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
|
||||
disk->ModeSelect(ctrl.cmd, GetBuffer(), ctrl.offset);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
@ -958,27 +896,27 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
// Special case Write function for brige
|
||||
// TODO This class must not know about SCSIBR
|
||||
if (auto bridge = dynamic_cast<SCSIBR *>(disk); bridge) {
|
||||
if (!bridge->WriteBytes(ctrl.cmd, ctrl.buffer, ctrl.length)) {
|
||||
if (!bridge->WriteBytes(ctrl.cmd, GetBuffer(), ctrl.length)) {
|
||||
// Write failed
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
break;
|
||||
}
|
||||
|
||||
// Special case Write function for DaynaPort
|
||||
// TODO This class must not know about DaynaPort
|
||||
if (auto daynaport = dynamic_cast<SCSIDaynaPort *>(disk); daynaport) {
|
||||
daynaport->WriteBytes(ctrl.cmd, ctrl.buffer, 0);
|
||||
daynaport->WriteBytes(ctrl.cmd, GetBuffer(), 0);
|
||||
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
ctrl.blocks = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
disk->Write(ctrl.cmd, ctrl.buffer, ctrl.next - 1);
|
||||
disk->Write(ctrl.cmd, GetBuffer(), ctrl.next - 1);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
@ -1002,7 +940,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1020,93 +958,94 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
|
||||
void ScsiController::ProcessCommand()
|
||||
{
|
||||
uint32_t len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
|
||||
uint32_t len = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
|
||||
|
||||
stringstream s;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
ctrl.cmd[i] = ctrl.buffer[i];
|
||||
LOGTRACE("%s Command Byte %d: $%02X",__PRETTY_FUNCTION__, i, ctrl.cmd[i])
|
||||
ctrl.cmd[i] = GetBuffer()[i];
|
||||
s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
|
||||
}
|
||||
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
|
||||
|
||||
Execute();
|
||||
}
|
||||
|
||||
void ScsiController::ParseMessage()
|
||||
{
|
||||
int i = 0;
|
||||
while (i < scsi.msc) {
|
||||
BYTE message_type = scsi.msb[i];
|
||||
|
||||
if (message_type == 0x06) {
|
||||
LOGTRACE("Received ABORT message")
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message_type == 0x0C) {
|
||||
LOGTRACE("Received BUS DEVICE RESET message")
|
||||
scsi.syncoffset = 0;
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message_type >= 0x80) {
|
||||
identified_lun = (int)message_type & 0x1F;
|
||||
LOGTRACE("Received IDENTIFY message for LUN %d", identified_lun)
|
||||
}
|
||||
|
||||
if (message_type == 0x01) {
|
||||
LOGTRACE("Received EXTENDED MESSAGE")
|
||||
|
||||
// Check only when synchronous transfer is possible
|
||||
if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) {
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
GetBuffer()[0] = 0x07;
|
||||
MsgIn();
|
||||
return;
|
||||
}
|
||||
|
||||
scsi.syncperiod = scsi.msb[i + 3];
|
||||
if (scsi.syncperiod > MAX_SYNC_PERIOD) {
|
||||
scsi.syncperiod = MAX_SYNC_PERIOD;
|
||||
}
|
||||
|
||||
scsi.syncoffset = scsi.msb[i + 4];
|
||||
if (scsi.syncoffset > MAX_SYNC_OFFSET) {
|
||||
scsi.syncoffset = MAX_SYNC_OFFSET;
|
||||
}
|
||||
|
||||
// STDR response message generation
|
||||
ctrl.length = 5;
|
||||
ctrl.blocks = 1;
|
||||
GetBuffer()[0] = 0x01;
|
||||
GetBuffer()[1] = 0x03;
|
||||
GetBuffer()[2] = 0x01;
|
||||
GetBuffer()[3] = scsi.syncperiod;
|
||||
GetBuffer()[4] = scsi.syncoffset;
|
||||
MsgIn();
|
||||
return;
|
||||
}
|
||||
|
||||
// Next message
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void ScsiController::ProcessMessage()
|
||||
{
|
||||
// Continue message out phase as long as ATN keeps asserting
|
||||
if (bus->GetATN()) {
|
||||
// Data transfer is 1 byte x 1 block
|
||||
ctrl.offset = 0;
|
||||
ResetOffset();
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Parsing messages sent by ATN
|
||||
if (scsi.atnmsg) {
|
||||
int i = 0;
|
||||
while (i < scsi.msc) {
|
||||
// Message type
|
||||
BYTE data = scsi.msb[i];
|
||||
|
||||
// ABORT
|
||||
if (data == 0x06) {
|
||||
LOGTRACE("Message code ABORT $%02X", data)
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
|
||||
// BUS DEVICE RESET
|
||||
if (data == 0x0C) {
|
||||
LOGTRACE("Message code BUS DEVICE RESET $%02X", data)
|
||||
scsi.syncoffset = 0;
|
||||
BusFree();
|
||||
return;
|
||||
}
|
||||
|
||||
// IDENTIFY
|
||||
if (data >= 0x80) {
|
||||
identified_lun = (int)data & 0x1F;
|
||||
LOGTRACE("Message code IDENTIFY $%02X, LUN %d selected", data, identified_lun)
|
||||
}
|
||||
|
||||
// Extended Message
|
||||
if (data == 0x01) {
|
||||
LOGTRACE("Message code EXTENDED MESSAGE $%02X", data)
|
||||
|
||||
// Check only when synchronous transfer is possible
|
||||
if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) {
|
||||
ctrl.length = 1;
|
||||
ctrl.blocks = 1;
|
||||
ctrl.buffer[0] = 0x07;
|
||||
MsgIn();
|
||||
return;
|
||||
}
|
||||
|
||||
scsi.syncperiod = scsi.msb[i + 3];
|
||||
if (scsi.syncperiod > MAX_SYNC_PERIOD) {
|
||||
scsi.syncperiod = MAX_SYNC_PERIOD;
|
||||
}
|
||||
|
||||
scsi.syncoffset = scsi.msb[i + 4];
|
||||
if (scsi.syncoffset > MAX_SYNC_OFFSET) {
|
||||
scsi.syncoffset = MAX_SYNC_OFFSET;
|
||||
}
|
||||
|
||||
// STDR response message generation
|
||||
ctrl.length = 5;
|
||||
ctrl.blocks = 1;
|
||||
ctrl.buffer[0] = 0x01;
|
||||
ctrl.buffer[1] = 0x03;
|
||||
ctrl.buffer[2] = 0x01;
|
||||
ctrl.buffer[3] = scsi.syncperiod;
|
||||
ctrl.buffer[4] = scsi.syncoffset;
|
||||
MsgIn();
|
||||
return;
|
||||
}
|
||||
|
||||
// next
|
||||
i++;
|
||||
}
|
||||
ParseMessage();
|
||||
}
|
||||
|
||||
// Initialize ATN message reception status
|
||||
|
@ -10,8 +10,6 @@
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI device controller ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
@ -53,8 +51,11 @@ class ScsiController : public AbstractController
|
||||
|
||||
public:
|
||||
|
||||
// Maximum number of logical units
|
||||
static const int LUN_MAX = 32;
|
||||
|
||||
ScsiController(shared_ptr<BUS>, int);
|
||||
~ScsiController () override;
|
||||
~ScsiController() override = default;
|
||||
ScsiController(ScsiController&) = delete;
|
||||
ScsiController& operator=(const ScsiController&) = delete;
|
||||
|
||||
@ -64,8 +65,6 @@ public:
|
||||
|
||||
int GetEffectiveLun() const override;
|
||||
|
||||
int GetMaxLuns() const override { return LUN_MAX; }
|
||||
|
||||
void Error(scsi_defs::sense_key sense_key, scsi_defs::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION) override;
|
||||
|
||||
@ -91,7 +90,6 @@ private:
|
||||
uint32_t bytes_to_transfer = 0;
|
||||
|
||||
// Phases
|
||||
void SetPhase(BUS::phase_t p) override { ctrl.phase = p; }
|
||||
void BusFree() override;
|
||||
void Selection() override;
|
||||
void Command() override;
|
||||
@ -101,7 +99,7 @@ private:
|
||||
// Data transfer
|
||||
void Send();
|
||||
bool XferMsg(int);
|
||||
bool XferIn(BYTE* buf);
|
||||
bool XferIn(vector<BYTE>&);
|
||||
bool XferOut(bool);
|
||||
bool XferOutBlockOriented(bool);
|
||||
void ReceiveBytes();
|
||||
@ -111,6 +109,7 @@ private:
|
||||
void Receive();
|
||||
|
||||
void ProcessCommand();
|
||||
void ParseMessage();
|
||||
void ProcessMessage();
|
||||
|
||||
void ScheduleShutdown(rascsi_shutdown_mode mode) override { shutdown_mode = mode; }
|
||||
|
@ -796,9 +796,6 @@ BYTE* CHostFilename::CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLas
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostFilename::ConvertHuman(int nCount)
|
||||
{
|
||||
char szHost[FILEPATH_MAX];
|
||||
|
||||
|
||||
// Don't do conversion for special directory names
|
||||
if (m_szHost[0] == '.' &&
|
||||
(m_szHost[1] == '\0' || (m_szHost[1] == '.' && m_szHost[2] == '\0'))) {
|
||||
@ -844,6 +841,7 @@ void CHostFilename::ConvertHuman(int nCount)
|
||||
BYTE* pExt = nullptr;
|
||||
|
||||
{
|
||||
char szHost[FILEPATH_MAX];
|
||||
strcpy(szHost, m_szHost);
|
||||
auto pRead = (const BYTE*)szHost;
|
||||
BYTE* pWrite = szHuman;
|
||||
@ -1558,8 +1556,7 @@ void CHostPath::Refresh()
|
||||
// If no match, confirm existence of real file
|
||||
strcpy(szPath, m_szHost);
|
||||
strcat(szPath, (const char*)pFilename->GetHuman());
|
||||
struct stat sb;
|
||||
if (stat(S2U(szPath), &sb))
|
||||
if (struct stat sb; stat(S2U(szPath), &sb))
|
||||
break; // Discover available patterns
|
||||
}
|
||||
}
|
||||
@ -1575,7 +1572,7 @@ void CHostPath::Refresh()
|
||||
strcpy(szPath, m_szHost);
|
||||
strcat(szPath, U2S(pe->d_name));
|
||||
|
||||
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
struct stat sb;
|
||||
if (stat(S2U(szPath), &sb))
|
||||
continue;
|
||||
|
||||
@ -1654,8 +1651,7 @@ void CHostPath::Backup()
|
||||
len--;
|
||||
assert(szPath[len] == '/');
|
||||
szPath[len] = '\0';
|
||||
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
if (stat(S2U(szPath), &sb) == 0)
|
||||
if (struct stat sb; stat(S2U(szPath), &sb) == 0)
|
||||
m_tBackup = sb.st_mtime;
|
||||
}
|
||||
}
|
||||
@ -2291,8 +2287,7 @@ bool CHostFcb::Create(DWORD, bool bForce)
|
||||
|
||||
// Duplication check
|
||||
if (!bForce) {
|
||||
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
if (stat(S2U(m_szFilename), &sb) == 0)
|
||||
if (struct stat sb; stat(S2U(m_szFilename), &sb) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2917,7 +2912,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
|
||||
// Generate attribute
|
||||
if (DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
|
||||
f.GetAttribute() != nAttribute) {
|
||||
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
struct stat sb;
|
||||
if (stat(S2U(f.GetPath()), &sb))
|
||||
return FS_FILENOTFND;
|
||||
mode_t m = sb.st_mode & 0777;
|
||||
|
@ -62,7 +62,7 @@ CTapDriver::~CTapDriver()
|
||||
LOGERROR("Can't open bridge socket: %s", strerror(errno))
|
||||
} else {
|
||||
LOGDEBUG("brctl delif %s ras0", BRIDGE_NAME)
|
||||
if (!br_setif(br_socket_fd, BRIDGE_NAME, "ras0", false)) {
|
||||
if (!br_setif(br_socket_fd, BRIDGE_NAME, "ras0", false)) { //NOSONAR No exception is raised here
|
||||
LOGWARN("Warning: Removing ras0 from the bridge failed.")
|
||||
LOGWARN("You may need to manually remove the ras0 tap device from the bridge")
|
||||
}
|
||||
@ -160,8 +160,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
LOGTRACE("Opened tap device %d", m_hTAP)
|
||||
|
||||
// IFF_NO_PI for no extra packet information
|
||||
ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifreq ifr = {};
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
string dev = "ras0";
|
||||
strncpy(ifr.ifr_name, dev.c_str(), IFNAMSIZ - 1);
|
||||
@ -262,10 +261,9 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
|
||||
// long long is required for compatibility with 32 bit platforms
|
||||
auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
|
||||
char buf[16];
|
||||
sprintf(buf, "%lld.%lld.%lld.%lld", (mask >> 24) & 0xff, (mask >> 16) & 0xff, (mask >> 8) & 0xff,
|
||||
mask & 0xff);
|
||||
netmask = buf;
|
||||
netmask = to_string((mask >> 24) & 0xff) + '.' + to_string((mask >> 16) & 0xff) + '.' +
|
||||
to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff);
|
||||
|
||||
}
|
||||
|
||||
LOGTRACE("brctl addbr %s", BRIDGE_NAME)
|
||||
|
@ -34,15 +34,6 @@ DeviceFactory::DeviceFactory()
|
||||
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
|
||||
sector_sizes[SCCD] = { 512, 2048};
|
||||
|
||||
// 128 MB, 512 bytes per sector, 248826 sectors
|
||||
geometries[SCMO][0x797f400] = make_pair(512, 248826);
|
||||
// 230 MB, 512 bytes per block, 446325 sectors
|
||||
geometries[SCMO][0xd9eea00] = make_pair(512, 446325);
|
||||
// 540 MB, 512 bytes per sector, 1041500 sectors
|
||||
geometries[SCMO][0x1fc8b800] = make_pair(512, 1041500);
|
||||
// 640 MB, 20248 bytes per sector, 310352 sectors
|
||||
geometries[SCMO][0x25e28000] = make_pair(2048, 310352);
|
||||
|
||||
string network_interfaces;
|
||||
for (const auto& network_interface : GetNetworkInterfaces()) {
|
||||
if (!network_interfaces.empty()) {
|
||||
@ -180,7 +171,7 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
|
||||
break;
|
||||
|
||||
case SCMO:
|
||||
device = make_unique<SCSIMO>(sector_sizes[SCMO], geometries[SCMO]);
|
||||
device = make_unique<SCSIMO>(sector_sizes[SCMO]);
|
||||
device->SetProtectable(true);
|
||||
device->SetStoppable(true);
|
||||
device->SetRemovable(true);
|
||||
@ -232,17 +223,17 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
|
||||
break;
|
||||
}
|
||||
|
||||
assert(device != nullptr);
|
||||
if (device != nullptr) {
|
||||
PrimaryDevice *d = device.release();
|
||||
|
||||
PrimaryDevice *d = device.release();
|
||||
|
||||
if (d != nullptr) {
|
||||
d->SetId(id);
|
||||
|
||||
devices.emplace(id, d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
return d;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const unordered_set<uint32_t>& DeviceFactory::GetSectorSizes(PbDeviceType type) const
|
||||
|
@ -21,8 +21,6 @@
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
using namespace rascsi_interface; //NOSONAR Not relevant for rascsi
|
||||
|
||||
using Geometry = pair<uint32_t, uint32_t>;
|
||||
|
||||
class PrimaryDevice;
|
||||
|
||||
class DeviceFactory
|
||||
@ -50,9 +48,6 @@ private:
|
||||
|
||||
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
|
||||
|
||||
// Optional mapping of drive capacities to drive geometries
|
||||
unordered_map<PbDeviceType, unordered_map<uint64_t, Geometry>> geometries;
|
||||
|
||||
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
|
||||
|
||||
unordered_map<string, PbDeviceType> extension_mapping;
|
||||
|
@ -60,20 +60,18 @@ Disk::Disk(const string& id) : ModePageDevice(id)
|
||||
Disk::~Disk()
|
||||
{
|
||||
// Save disk cache, only if ready
|
||||
if (IsReady() && disk.dcache) {
|
||||
disk.dcache->Save();
|
||||
if (IsReady() && cache != nullptr) {
|
||||
cache->Save();
|
||||
}
|
||||
|
||||
delete disk.dcache;
|
||||
}
|
||||
|
||||
bool Disk::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// Media changes must be reported on the next access, i.e. not only for TEST UNIT READY
|
||||
if (disk.is_medium_changed) {
|
||||
if (is_medium_changed) {
|
||||
assert(IsRemovable());
|
||||
|
||||
disk.is_medium_changed = false;
|
||||
is_medium_changed = false;
|
||||
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
}
|
||||
@ -90,14 +88,10 @@ bool Disk::Dispatch(scsi_command cmd)
|
||||
//---------------------------------------------------------------------------
|
||||
void Disk::Open(const Filepath& path)
|
||||
{
|
||||
assert(disk.blocks > 0);
|
||||
assert(blocks > 0);
|
||||
|
||||
SetReady(true);
|
||||
|
||||
// Cache initialization
|
||||
assert (!disk.dcache);
|
||||
disk.dcache = new DiskCache(path, disk.size, (uint32_t)disk.blocks, disk.image_offset);
|
||||
|
||||
// Can read/write open
|
||||
if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) {
|
||||
// Write permission
|
||||
@ -114,10 +108,16 @@ void Disk::Open(const Filepath& path)
|
||||
SetLocked(false);
|
||||
}
|
||||
|
||||
void Disk::SetUpCache(const Filepath& path, off_t image_offset)
|
||||
{
|
||||
assert(cache == nullptr);
|
||||
cache = make_unique<DiskCache>(path, size_shift_count, (uint32_t)blocks, image_offset);
|
||||
}
|
||||
|
||||
void Disk::FlushCache()
|
||||
{
|
||||
if (disk.dcache) {
|
||||
disk.dcache->Save();
|
||||
if (cache != nullptr) {
|
||||
cache->Save();
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +146,8 @@ void Disk::ReassignBlocks()
|
||||
void Disk::Read(access_mode mode)
|
||||
{
|
||||
if (uint64_t start; CheckAndGetStartAndCount(start, ctrl->blocks, mode)) {
|
||||
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
|
||||
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, controller->GetLength())
|
||||
|
||||
// Set next block
|
||||
ctrl->next = start + 1;
|
||||
@ -177,7 +177,7 @@ void Disk::Read16()
|
||||
void Disk::ReadWriteLong10()
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (ctrl->cmd[7] || ctrl->cmd[8]) {
|
||||
if (GetInt16(ctrl->cmd, 7) != 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ void Disk::ReadWriteLong10()
|
||||
void Disk::ReadWriteLong16()
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (ctrl->cmd[12] || ctrl->cmd[13]) {
|
||||
if (GetInt16(ctrl->cmd, 12) != 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
@ -238,7 +238,7 @@ void Disk::Verify(access_mode mode)
|
||||
}
|
||||
|
||||
// Test reading
|
||||
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
|
||||
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
|
||||
|
||||
// Set next block
|
||||
ctrl->next = start + 1;
|
||||
@ -331,24 +331,22 @@ void Disk::SynchronizeCache()
|
||||
|
||||
void Disk::ReadDefectData10()
|
||||
{
|
||||
int allocation_length = GetInt16(ctrl->cmd, 7);
|
||||
if (allocation_length > 4) {
|
||||
allocation_length = 4;
|
||||
}
|
||||
size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
|
||||
|
||||
// The defect list is empty
|
||||
memset(ctrl->buffer, 0, allocation_length);
|
||||
ctrl->length = allocation_length;
|
||||
fill_n(controller->GetBuffer().begin(), allocation_length, 0);
|
||||
ctrl->length = (int)allocation_length;
|
||||
|
||||
EnterDataInPhase();
|
||||
}
|
||||
|
||||
void Disk::MediumChanged()
|
||||
{
|
||||
assert(IsRemovable());
|
||||
|
||||
if (IsRemovable()) {
|
||||
disk.is_medium_changed = true;
|
||||
is_medium_changed = true;
|
||||
}
|
||||
else {
|
||||
LOGWARN("%s Medium change requested for non-reomvable medium", __PRETTY_FUNCTION__)
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,11 +355,9 @@ bool Disk::Eject(bool force)
|
||||
bool status = super::Eject(force);
|
||||
if (status) {
|
||||
FlushCache();
|
||||
delete disk.dcache;
|
||||
disk.dcache = nullptr;
|
||||
cache.reset();
|
||||
|
||||
// The image file for this drive is not in use anymore
|
||||
// TODO This cast and the FileSupport class can be removed as soon as only disk-like devices inherit from Disk
|
||||
if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) {
|
||||
file_support->UnreserveFile();
|
||||
}
|
||||
@ -370,14 +366,11 @@ bool Disk::Eject(bool force)
|
||||
return status;
|
||||
}
|
||||
|
||||
int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
auto length = cdb[4];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
memset(buf, 0, length);
|
||||
auto length = (int)min((size_t)max_length, (size_t)cdb[4]);
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// DEVICE SPECIFIC PARAMETER
|
||||
if (IsProtected()) {
|
||||
@ -385,7 +378,7 @@ int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
}
|
||||
|
||||
// Basic information
|
||||
int size = 4;
|
||||
int info_size = 4;
|
||||
|
||||
// Add block descriptor if DBD is 0
|
||||
if ((cdb[1] & 0x08) == 0) {
|
||||
@ -395,37 +388,34 @@ int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
// Only if ready
|
||||
if (IsReady()) {
|
||||
// Short LBA mode parameter block descriptor (number of blocks and block length)
|
||||
SetInt32(&buf[4], (uint32_t)GetBlockCount());
|
||||
SetInt32(&buf[8], GetSectorSizeInBytes());
|
||||
SetInt32(buf, 4, (uint32_t)GetBlockCount());
|
||||
SetInt32(buf, 8, GetSectorSizeInBytes());
|
||||
}
|
||||
|
||||
size = 12;
|
||||
info_size = 12;
|
||||
}
|
||||
|
||||
size += super::AddModePages(cdb, &buf[size], length - size);
|
||||
if (size > 255) {
|
||||
info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
|
||||
if (info_size > 255) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
if (size > length) {
|
||||
size = length;
|
||||
if (info_size > length) {
|
||||
info_size = length;
|
||||
}
|
||||
|
||||
// Final setting of mode data length
|
||||
buf[0] = (BYTE)size;
|
||||
buf[0] = (BYTE)info_size;
|
||||
|
||||
return size;
|
||||
return info_size;
|
||||
}
|
||||
|
||||
int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
int length = GetInt16(cdb, 7);
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
memset(buf, 0, length);
|
||||
auto length = (int)min((size_t)max_length, (size_t)GetInt16(cdb, 7));
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// DEVICE SPECIFIC PARAMETER
|
||||
if (IsProtected()) {
|
||||
@ -433,7 +423,7 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
}
|
||||
|
||||
// Basic Information
|
||||
int size = 8;
|
||||
int info_size = 8;
|
||||
|
||||
// Add block descriptor if DBD is 0, only if ready
|
||||
if ((cdb[1] & 0x08) == 0 && IsReady()) {
|
||||
@ -446,10 +436,10 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
buf[7] = 0x08;
|
||||
|
||||
// Short LBA mode parameter block descriptor (number of blocks and block length)
|
||||
SetInt32(&buf[8], (uint32_t)disk_blocks);
|
||||
SetInt32(&buf[12], disk_size);
|
||||
SetInt32(buf, 8, (uint32_t)disk_blocks);
|
||||
SetInt32(buf, 12, disk_size);
|
||||
|
||||
size = 16;
|
||||
info_size = 16;
|
||||
}
|
||||
else {
|
||||
// Mode parameter header, LONGLBA
|
||||
@ -459,27 +449,27 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
buf[7] = 0x10;
|
||||
|
||||
// Long LBA mode parameter block descriptor (number of blocks and block length)
|
||||
SetInt64(&buf[8], disk_blocks);
|
||||
SetInt32(&buf[20], disk_size);
|
||||
SetInt64(buf, 8, disk_blocks);
|
||||
SetInt32(buf, 20, disk_size);
|
||||
|
||||
size = 24;
|
||||
info_size = 24;
|
||||
}
|
||||
}
|
||||
|
||||
size += super::AddModePages(cdb, &buf[size], length - size);
|
||||
if (size > 65535) {
|
||||
info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
|
||||
if (info_size > 65535) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
if (size > length) {
|
||||
size = length;
|
||||
if (info_size > length) {
|
||||
info_size = length;
|
||||
}
|
||||
|
||||
// Final setting of mode data length
|
||||
SetInt16(buf, size);
|
||||
SetInt16(buf, 0, info_size);
|
||||
|
||||
return size;
|
||||
return info_size;
|
||||
}
|
||||
|
||||
void Disk::SetUpModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
|
||||
@ -536,7 +526,7 @@ void Disk::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
SetInt16(buf, 0x0a, 25);
|
||||
|
||||
// Set the number of bytes in the physical sector
|
||||
SetInt16(buf, 0x0c, 1 << disk.size);
|
||||
SetInt16(buf, 0x0c, 1 << size_shift_count);
|
||||
|
||||
// Interleave 1
|
||||
SetInt16(buf, 0x0e, 1);
|
||||
@ -570,7 +560,7 @@ void Disk::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
if (IsReady()) {
|
||||
// Set the number of cylinders (total number of blocks
|
||||
// divided by 25 sectors/track and 8 heads)
|
||||
uint64_t cylinders = disk.blocks;
|
||||
uint64_t cylinders = blocks;
|
||||
cylinders >>= 3;
|
||||
cylinders /= 25;
|
||||
SetInt32(buf, 0x01, (uint32_t)cylinders);
|
||||
@ -616,24 +606,24 @@ void Disk::AddVendorPage(map<int, vector<byte>>&, int, bool) const
|
||||
}
|
||||
|
||||
// TODO Read more than one block in a single call. Currently blocked by the the track-oriented cache
|
||||
int Disk::Read(const vector<int>&, BYTE *buf, uint64_t block)
|
||||
int Disk::Read(const vector<int>&, vector<BYTE>& buf, uint64_t block)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
CheckReady();
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= disk.blocks) {
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// leave it to the cache
|
||||
if (!disk.dcache->ReadSector(buf, (uint32_t)block)) {
|
||||
if (!cache->ReadSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
|
||||
}
|
||||
|
||||
// Success
|
||||
return 1 << disk.size;
|
||||
return 1 << size_shift_count;
|
||||
}
|
||||
|
||||
int Disk::WriteCheck(uint64_t block)
|
||||
@ -641,7 +631,7 @@ int Disk::WriteCheck(uint64_t block)
|
||||
CheckReady();
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= disk.blocks) {
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
@ -651,11 +641,11 @@ int Disk::WriteCheck(uint64_t block)
|
||||
}
|
||||
|
||||
// Success
|
||||
return 1 << disk.size;
|
||||
return 1 << size_shift_count;
|
||||
}
|
||||
|
||||
// TODO Write more than one block in a single call. Currently blocked by the track-oriented cache
|
||||
void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
|
||||
void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
@ -665,7 +655,7 @@ void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
|
||||
}
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= disk.blocks) {
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
@ -675,7 +665,7 @@ void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
|
||||
}
|
||||
|
||||
// Leave it to the cache
|
||||
if (!disk.dcache->WriteSector(buf, (uint32_t)block)) {
|
||||
if (!cache->WriteSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
|
||||
}
|
||||
}
|
||||
@ -709,23 +699,23 @@ void Disk::ReadCapacity10()
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
if (disk.blocks == 0) {
|
||||
if (blocks == 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
BYTE *buf = ctrl->buffer;
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
|
||||
// Create end of logical block address (disk.blocks-1)
|
||||
uint64_t blocks = disk.blocks - 1;
|
||||
// Create end of logical block address (blocks-1)
|
||||
uint64_t capacity = blocks - 1;
|
||||
|
||||
// If the capacity exceeds 32 bit, -1 must be returned and the client has to use READ CAPACITY(16)
|
||||
if (blocks > 4294967295) {
|
||||
blocks = -1;
|
||||
if (capacity > 4294967295) {
|
||||
capacity = -1;
|
||||
}
|
||||
SetInt32(&buf[0], (uint32_t)blocks);
|
||||
SetInt32(buf, 0, (uint32_t)capacity);
|
||||
|
||||
// Create block length (1 << disk.size)
|
||||
SetInt32(&buf[4], 1 << disk.size);
|
||||
// Create block length (1 << size)
|
||||
SetInt32(buf, 4, 1 << size_shift_count);
|
||||
|
||||
// the size
|
||||
ctrl->length = 8;
|
||||
@ -737,17 +727,17 @@ void Disk::ReadCapacity16()
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
if (disk.blocks == 0) {
|
||||
if (blocks == 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
BYTE *buf = ctrl->buffer;
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
|
||||
// Create end of logical block address (disk.blocks-1)
|
||||
SetInt64(&buf[0], disk.blocks - 1);
|
||||
// Create end of logical block address (blocks-1)
|
||||
SetInt64(buf, 0, blocks - 1);
|
||||
|
||||
// Create block length (1 << disk.size)
|
||||
SetInt32(&buf[8], 1 << disk.size);
|
||||
// Create block length (1 << size)
|
||||
SetInt32(buf, 8, 1 << size_shift_count);
|
||||
|
||||
buf[12] = 0;
|
||||
|
||||
@ -820,11 +810,7 @@ void Disk::ValidateBlockAddress(access_mode mode) const
|
||||
bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mode mode) const
|
||||
{
|
||||
if (mode == RW6 || mode == SEEK6) {
|
||||
start = ctrl->cmd[1] & 0x1f;
|
||||
start <<= 8;
|
||||
start |= ctrl->cmd[2];
|
||||
start <<= 8;
|
||||
start |= ctrl->cmd[3];
|
||||
start = GetInt24(ctrl->cmd, 1);
|
||||
|
||||
count = ctrl->cmd[4];
|
||||
if (!count) {
|
||||
@ -864,7 +850,7 @@ bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mod
|
||||
|
||||
uint32_t Disk::GetSectorSizeInBytes() const
|
||||
{
|
||||
return disk.size ? 1 << disk.size : 0;
|
||||
return size_shift_count ? 1 << size_shift_count : 0;
|
||||
}
|
||||
|
||||
void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
|
||||
@ -877,19 +863,19 @@ void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
|
||||
|
||||
switch (size_in_bytes) {
|
||||
case 512:
|
||||
disk.size = 9;
|
||||
size_shift_count = 9;
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
disk.size = 10;
|
||||
size_shift_count = 10;
|
||||
break;
|
||||
|
||||
case 2048:
|
||||
disk.size = 11;
|
||||
size_shift_count = 11;
|
||||
break;
|
||||
|
||||
case 4096:
|
||||
disk.size = 12;
|
||||
size_shift_count = 12;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -898,49 +884,19 @@ void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Disk::GetSectorSizeShiftCount() const
|
||||
{
|
||||
return disk.size;
|
||||
}
|
||||
|
||||
void Disk::SetSectorSizeShiftCount(uint32_t shift_count)
|
||||
{
|
||||
disk.size = shift_count;
|
||||
}
|
||||
|
||||
bool Disk::IsSectorSizeConfigurable() const
|
||||
{
|
||||
return !sector_sizes.empty();
|
||||
}
|
||||
|
||||
void Disk::SetSectorSizes(const unordered_set<uint32_t>& sizes)
|
||||
{
|
||||
sector_sizes = sizes;
|
||||
}
|
||||
|
||||
uint32_t Disk::GetConfiguredSectorSize() const
|
||||
{
|
||||
return configured_sector_size;
|
||||
}
|
||||
|
||||
bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t size)
|
||||
bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t configured_size)
|
||||
{
|
||||
if (unordered_set<uint32_t> sizes = device_factory.GetSectorSizes(GetType());
|
||||
sizes.find(size) == sizes.end()) {
|
||||
sizes.find(configured_size) == sizes.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
configured_sector_size = size;
|
||||
configured_sector_size = configured_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t Disk::GetBlockCount() const
|
||||
{
|
||||
return disk.blocks;
|
||||
}
|
||||
|
||||
void Disk::SetBlockCount(uint64_t blocks)
|
||||
{
|
||||
disk.blocks = blocks;
|
||||
}
|
||||
|
@ -29,19 +29,19 @@ class Disk : public ModePageDevice, public ScsiBlockCommands
|
||||
{
|
||||
enum access_mode { RW6, RW10, RW16, SEEK6, SEEK10 };
|
||||
|
||||
// The supported configurable block sizes, empty if not configurable
|
||||
Dispatcher<Disk> dispatcher;
|
||||
|
||||
// The supported configurable sector sizes, empty if not configurable
|
||||
unordered_set<uint32_t> sector_sizes;
|
||||
uint32_t configured_sector_size = 0;
|
||||
|
||||
using disk_t = struct {
|
||||
uint32_t size; // Sector Size (9=512, 10=1024, 11=2048, 12=4096)
|
||||
uint64_t blocks; // Total number of sectors
|
||||
DiskCache *dcache; // Disk cache
|
||||
off_t image_offset; // Offset to actual data
|
||||
bool is_medium_changed;
|
||||
};
|
||||
// Sector size shift count (9=512, 10=1024, 11=2048, 12=4096)
|
||||
uint32_t size_shift_count = 0;
|
||||
|
||||
Dispatcher<Disk> dispatcher;
|
||||
// Total number of sectors
|
||||
uint64_t blocks = 0;
|
||||
|
||||
bool is_medium_changed = false;
|
||||
|
||||
public:
|
||||
|
||||
@ -57,14 +57,14 @@ public:
|
||||
|
||||
// Command helpers
|
||||
virtual int WriteCheck(uint64_t);
|
||||
virtual void Write(const vector<int>&, const BYTE *, uint64_t);
|
||||
virtual void Write(const vector<int>&, const vector<BYTE>&, uint64_t);
|
||||
|
||||
virtual int Read(const vector<int>&, BYTE *, uint64_t);
|
||||
virtual int Read(const vector<int>&, vector<BYTE>& , uint64_t);
|
||||
|
||||
uint32_t GetSectorSizeInBytes() const;
|
||||
bool IsSectorSizeConfigurable() const;
|
||||
bool IsSectorSizeConfigurable() const { return !sector_sizes.empty(); }
|
||||
bool SetConfiguredSectorSize(const DeviceFactory&, uint32_t);
|
||||
uint64_t GetBlockCount() const;
|
||||
uint64_t GetBlockCount() const { return blocks; }
|
||||
void FlushCache() override;
|
||||
|
||||
private:
|
||||
@ -105,12 +105,13 @@ private:
|
||||
void ValidateBlockAddress(access_mode) const;
|
||||
bool CheckAndGetStartAndCount(uint64_t&, uint32_t&, access_mode) const;
|
||||
|
||||
int ModeSense6(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense10(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense6(const vector<int>&, vector<BYTE>&, int) const override;
|
||||
int ModeSense10(const vector<int>&, vector<BYTE>&, int) const override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Open(const Filepath&);
|
||||
void SetUpCache(const Filepath&, off_t = 0);
|
||||
|
||||
void SetUpModePages(map<int, vector<byte>>&, int, bool) const override;
|
||||
virtual void AddErrorPage(map<int, vector<byte>>&, bool) const;
|
||||
@ -119,13 +120,12 @@ protected:
|
||||
void AddCachePage(map<int, vector<byte>>&, bool) const;
|
||||
virtual void AddVendorPage(map<int, vector<byte>>&, int, bool) const;
|
||||
unordered_set<uint32_t> GetSectorSizes() const;
|
||||
void SetSectorSizes(const unordered_set<uint32_t>&);
|
||||
void SetSectorSizes(const unordered_set<uint32_t>& sizes) { sector_sizes = sizes; }
|
||||
void SetSectorSizeInBytes(uint32_t);
|
||||
uint32_t GetSectorSizeShiftCount() const;
|
||||
void SetSectorSizeShiftCount(uint32_t);
|
||||
uint32_t GetSectorSizeShiftCount() const { return size_shift_count; }
|
||||
void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; }
|
||||
uint32_t GetConfiguredSectorSize() const;
|
||||
void SetBlockCount(uint64_t);
|
||||
void SetBlockCount(uint64_t b) { blocks = b; }
|
||||
|
||||
// Internal disk data
|
||||
disk_t disk = {};
|
||||
unique_ptr<DiskCache> cache;
|
||||
};
|
||||
|
@ -14,7 +14,6 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "log.h"
|
||||
#include "disk_track.h"
|
||||
#include "disk_cache.h"
|
||||
|
||||
@ -27,18 +26,6 @@ DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgo
|
||||
sec_path = path;
|
||||
}
|
||||
|
||||
DiskCache::~DiskCache()
|
||||
{
|
||||
// Clear the track
|
||||
Clear();
|
||||
}
|
||||
|
||||
void DiskCache::SetRawMode(bool raw)
|
||||
{
|
||||
// Configuration
|
||||
cd_raw = raw;
|
||||
}
|
||||
|
||||
bool DiskCache::Save() const
|
||||
{
|
||||
// Save track
|
||||
@ -52,50 +39,21 @@ bool DiskCache::Save() const
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Get disk cache information
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::GetCache(int index, int& track, uint32_t& aserial) const
|
||||
shared_ptr<DiskTrack> DiskCache::GetTrack(uint32_t block)
|
||||
{
|
||||
assert((index >= 0) && (index < CACHE_MAX));
|
||||
|
||||
// false if unused
|
||||
if (!cache[index].disktrk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set track and serial
|
||||
track = cache[index].disktrk->GetTrack();
|
||||
aserial = cache[index].serial;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskCache::Clear()
|
||||
{
|
||||
// Free the cache
|
||||
for (cache_t& c : cache) {
|
||||
if (c.disktrk) {
|
||||
delete c.disktrk;
|
||||
c.disktrk = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskCache::ReadSector(BYTE *buf, uint32_t block)
|
||||
{
|
||||
assert(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
||||
// Calculate track (fixed to 256 sectors/track)
|
||||
int track = block >> 8;
|
||||
|
||||
// Get the track data
|
||||
const DiskTrack *disktrk = Assign(track);
|
||||
// Get track data
|
||||
return Assign(track);
|
||||
}
|
||||
|
||||
bool DiskCache::ReadSector(vector<BYTE>& buf, uint32_t block)
|
||||
{
|
||||
shared_ptr<DiskTrack> disktrk = GetTrack(block);
|
||||
if (disktrk == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -104,18 +62,9 @@ bool DiskCache::ReadSector(BYTE *buf, uint32_t block)
|
||||
return disktrk->ReadSector(buf, block & 0xff);
|
||||
}
|
||||
|
||||
bool DiskCache::WriteSector(const BYTE *buf, uint32_t block)
|
||||
bool DiskCache::WriteSector(const vector<BYTE>& buf, uint32_t block)
|
||||
{
|
||||
assert(sec_size != 0);
|
||||
|
||||
// Update first
|
||||
UpdateSerialNumber();
|
||||
|
||||
// Calculate track (fixed to 256 sectors/track)
|
||||
int track = block >> 8;
|
||||
|
||||
// Get that track data
|
||||
DiskTrack *disktrk = Assign(track);
|
||||
shared_ptr<DiskTrack> disktrk = GetTrack(block);
|
||||
if (disktrk == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -129,7 +78,7 @@ bool DiskCache::WriteSector(const BYTE *buf, uint32_t block)
|
||||
// Track Assignment
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DiskTrack* DiskCache::Assign(int track)
|
||||
shared_ptr<DiskTrack> DiskCache::Assign(int track)
|
||||
{
|
||||
assert(sec_size != 0);
|
||||
assert(track >= 0);
|
||||
@ -144,10 +93,10 @@ DiskTrack* DiskCache::Assign(int track)
|
||||
}
|
||||
|
||||
// Next, check for empty
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
if (!cache[i].disktrk) {
|
||||
for (size_t i = 0; i < cache.size(); i++) {
|
||||
if (cache[i].disktrk == nullptr) {
|
||||
// Try loading
|
||||
if (Load(i, track)) {
|
||||
if (Load((int)i, track, nullptr)) {
|
||||
// Success loading
|
||||
cache[i].serial = serial;
|
||||
return cache[i].disktrk;
|
||||
@ -162,10 +111,10 @@ DiskTrack* DiskCache::Assign(int track)
|
||||
|
||||
// Set index 0 as candidate c
|
||||
uint32_t s = cache[0].serial;
|
||||
int c = 0;
|
||||
size_t c = 0;
|
||||
|
||||
// Compare candidate with serial and update to smaller one
|
||||
for (int i = 0; i < CACHE_MAX; i++) {
|
||||
for (size_t i = 0; i < cache.size(); i++) {
|
||||
assert(cache[i].disktrk);
|
||||
|
||||
// Compare and update the existing serial
|
||||
@ -181,10 +130,10 @@ DiskTrack* DiskCache::Assign(int track)
|
||||
}
|
||||
|
||||
// Delete this track
|
||||
DiskTrack *disktrk = cache[c].disktrk;
|
||||
cache[c].disktrk = nullptr;
|
||||
shared_ptr<DiskTrack> disktrk = cache[c].disktrk;
|
||||
cache[c].disktrk.reset();
|
||||
|
||||
if (Load(c, track, disktrk)) {
|
||||
if (Load((int)c, track, disktrk)) {
|
||||
// Successful loading
|
||||
cache[c].serial = serial;
|
||||
return cache[c].disktrk;
|
||||
@ -199,11 +148,11 @@ DiskTrack* DiskCache::Assign(int track)
|
||||
// Load cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||||
bool DiskCache::Load(int index, int track, shared_ptr<DiskTrack> disktrk)
|
||||
{
|
||||
assert((index >= 0) && (index < CACHE_MAX));
|
||||
assert(index >= 0 && index < (int)cache.size());
|
||||
assert(track >= 0);
|
||||
assert(!cache[index].disktrk);
|
||||
assert(cache[index].disktrk == nullptr);
|
||||
|
||||
// Get the number of sectors on this track
|
||||
int sectors = sec_blocks - (track << 8);
|
||||
@ -214,7 +163,7 @@ bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||||
|
||||
// Create a disk track
|
||||
if (disktrk == nullptr) {
|
||||
disktrk = new DiskTrack();
|
||||
disktrk = make_shared<DiskTrack>();
|
||||
}
|
||||
|
||||
// Initialize disk track
|
||||
@ -223,7 +172,6 @@ bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||||
// Try loading
|
||||
if (!disktrk->Load(sec_path)) {
|
||||
// Failure
|
||||
delete disktrk;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -16,43 +16,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
// Number of tracks to cache
|
||||
static const int CACHE_MAX = 16;
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
class DiskCache
|
||||
{
|
||||
// Number of tracks to cache
|
||||
static const int CACHE_MAX = 16;
|
||||
|
||||
public:
|
||||
|
||||
// Internal data definition
|
||||
using cache_t = struct {
|
||||
DiskTrack *disktrk; // Disk Track
|
||||
uint32_t serial; // Serial
|
||||
shared_ptr<DiskTrack> disktrk; // Disk Track
|
||||
uint32_t serial; // Serial
|
||||
};
|
||||
|
||||
DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
|
||||
~DiskCache();
|
||||
~DiskCache() = default;
|
||||
DiskCache(DiskCache&) = delete;
|
||||
DiskCache& operator=(const DiskCache&) = delete;
|
||||
|
||||
void SetRawMode(bool); // CD-ROM raw mode setting
|
||||
void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting
|
||||
|
||||
// Access
|
||||
bool Save() const; // Save and release all
|
||||
bool ReadSector(BYTE *buf, uint32_t block); // Sector Read
|
||||
bool WriteSector(const BYTE *buf, uint32_t block); // Sector Write
|
||||
bool GetCache(int index, int& track, uint32_t& serial) const; // Get cache information
|
||||
bool ReadSector(vector<BYTE>&, uint32_t); // Sector Read
|
||||
bool WriteSector(const vector<BYTE>&, uint32_t); // Sector Write
|
||||
|
||||
private:
|
||||
|
||||
// Internal Management
|
||||
void Clear(); // Clear all tracks
|
||||
DiskTrack* Assign(int track); // Load track
|
||||
bool Load(int index, int track, DiskTrack *disktrk = nullptr); // Load track
|
||||
void UpdateSerialNumber(); // Update serial number
|
||||
shared_ptr<DiskTrack> Assign(int);
|
||||
shared_ptr<DiskTrack> GetTrack(uint32_t);
|
||||
bool Load(int index, int track, shared_ptr<DiskTrack>);
|
||||
void UpdateSerialNumber();
|
||||
|
||||
// Internal data
|
||||
cache_t cache[CACHE_MAX] = {}; // Cache management
|
||||
array<cache_t, CACHE_MAX> cache = {}; // Cache management
|
||||
uint32_t serial = 0; // Last serial number
|
||||
Filepath sec_path; // Path
|
||||
int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
|
@ -24,9 +24,6 @@ DiskTrack::~DiskTrack()
|
||||
if (dt.buffer) {
|
||||
free(dt.buffer);
|
||||
}
|
||||
if (dt.changemap) {
|
||||
free(dt.changemap);
|
||||
}
|
||||
}
|
||||
|
||||
void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
|
||||
@ -56,7 +53,6 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
// Not needed if already loaded
|
||||
if (dt.init) {
|
||||
assert(dt.buffer);
|
||||
assert(dt.changemap);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -86,7 +82,7 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
if (!dt.buffer) {
|
||||
if (dt.buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,31 +95,16 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
dt.length = length;
|
||||
}
|
||||
|
||||
// Reserve change map memory
|
||||
if (dt.changemap == nullptr) {
|
||||
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
||||
dt.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
if (!dt.changemap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reallocate if the buffer length is different
|
||||
if (dt.maplen != (DWORD)dt.sectors) {
|
||||
free(dt.changemap);
|
||||
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
||||
dt.maplen = dt.sectors;
|
||||
}
|
||||
|
||||
// Clear changemap
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
||||
// Resize and clear changemap
|
||||
dt.changemap.resize(dt.sectors);
|
||||
fill(dt.changemap.begin(), dt.changemap.end(), false);
|
||||
|
||||
// Read from File
|
||||
Fileio fio;
|
||||
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dt.raw) {
|
||||
// Split Reading
|
||||
for (int i = 0; i < dt.sectors; i++) {
|
||||
@ -175,7 +156,6 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
|
||||
// Need to write
|
||||
assert(dt.buffer);
|
||||
assert(dt.changemap);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
||||
// Writing in RAW mode is not allowed
|
||||
@ -237,18 +217,18 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
}
|
||||
}
|
||||
|
||||
// Close
|
||||
fio.Close();
|
||||
|
||||
// Drop the change flag and exit
|
||||
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
||||
fill(dt.changemap.begin(), dt.changemap.end(), false);
|
||||
dt.changed = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::ReadSector(BYTE *buf, int sec) const
|
||||
bool DiskTrack::ReadSector(vector<BYTE>& buf, int sec) const
|
||||
{
|
||||
assert((sec >= 0) && (sec < 0x100));
|
||||
assert(sec >= 0 && sec < 0x100);
|
||||
|
||||
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
|
||||
|
||||
@ -265,13 +245,13 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
|
||||
// Copy
|
||||
assert(dt.buffer);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
|
||||
memcpy(buf.data(), &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
||||
bool DiskTrack::WriteSector(const vector<BYTE>& buf, int sec)
|
||||
{
|
||||
assert((sec >= 0) && (sec < 0x100));
|
||||
assert(!dt.raw);
|
||||
@ -293,13 +273,13 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
|
||||
// Compare
|
||||
assert(dt.buffer);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
if (memcmp(buf, &dt.buffer[offset], length) == 0) {
|
||||
if (memcmp(buf.data(), &dt.buffer[offset], length) == 0) {
|
||||
// Exit normally since it's attempting to write the same thing
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy, change
|
||||
memcpy(&dt.buffer[offset], buf, length);
|
||||
memcpy(&dt.buffer[offset], buf.data(), length);
|
||||
dt.changemap[sec] = true;
|
||||
dt.changed = true;
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
class DiskTrack
|
||||
{
|
||||
@ -27,8 +30,7 @@ class DiskTrack
|
||||
BYTE *buffer; // Data buffer
|
||||
bool init; // Is it initilized?
|
||||
bool changed; // Changed flag
|
||||
DWORD maplen; // Changed map length
|
||||
bool *changemap; // Changed map
|
||||
std::vector<bool> changemap; // Changed map
|
||||
bool raw; // RAW mode flag
|
||||
off_t imgoffset; // Offset to actual data
|
||||
} dt = {};
|
||||
@ -49,8 +51,8 @@ private:
|
||||
bool Save(const Filepath& path);
|
||||
|
||||
// Read / Write
|
||||
bool ReadSector(BYTE *buf, int sec) const; // Sector Read
|
||||
bool WriteSector(const BYTE *buf, int sec); // Sector Write
|
||||
bool ReadSector(vector<BYTE>&, int) const; // Sector Read
|
||||
bool WriteSector(const vector<BYTE>& buf, int); // Sector Write
|
||||
|
||||
int GetTrack() const { return dt.track; } // Get track
|
||||
};
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "scsi_command_util.h"
|
||||
#include "dispatcher.h"
|
||||
#include "host_services.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace scsi_defs;
|
||||
using namespace scsi_command_util;
|
||||
@ -85,23 +86,20 @@ void HostServices::StartStopUnit()
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
int HostServices::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
int length = cdb[4];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
memset(buf, 0, length);
|
||||
auto length = (int)min((size_t)max_length, (size_t)cdb[4]);
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// Basic Information
|
||||
int size = 4;
|
||||
|
||||
size += super::AddModePages(cdb, &buf[size], length - size);
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 255) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
@ -116,23 +114,20 @@ int HostServices::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length)
|
||||
return size;
|
||||
}
|
||||
|
||||
int HostServices::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
int HostServices::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
int length = (cdb[7] << 8) | cdb[8];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
memset(buf, 0, length);
|
||||
auto length = (int)min((size_t)max_length, (size_t)GetInt16(cdb, 7));
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// Basic Information
|
||||
int size = 8;
|
||||
|
||||
size += super::AddModePages(cdb, &buf[size], length - size);
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 65535) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
@ -142,7 +137,7 @@ int HostServices::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length)
|
||||
size = length;
|
||||
}
|
||||
|
||||
SetInt16(buf, size);
|
||||
SetInt16(buf, 0, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -157,7 +152,7 @@ void HostServices::SetUpModePages(map<int, vector<byte>>& pages, int page, bool
|
||||
void HostServices::AddRealtimeClockPage(map<int, vector<byte>>& pages, bool changeable) const
|
||||
{
|
||||
if (!changeable) {
|
||||
std::time_t t = std::time(nullptr);
|
||||
time_t t = time(nullptr);
|
||||
tm localtime;
|
||||
localtime_r(&t, &localtime);
|
||||
|
||||
|
@ -58,8 +58,8 @@ private:
|
||||
|
||||
Dispatcher<HostServices> dispatcher;
|
||||
|
||||
int ModeSense6(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense10(const vector<int>&, BYTE *, int) const override;
|
||||
int ModeSense6(const vector<int>&, vector<BYTE>&, int) const override;
|
||||
int ModeSense10(const vector<int>&, vector<BYTE>&, int) const override;
|
||||
|
||||
void AddRealtimeClockPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
|
@ -11,12 +11,14 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "dispatcher.h"
|
||||
#include "mode_page_device.h"
|
||||
#include <cstddef>
|
||||
|
||||
using namespace std;
|
||||
using namespace scsi_defs;
|
||||
using namespace scsi_command_util;
|
||||
|
||||
ModePageDevice::ModePageDevice(const string& id) : PrimaryDevice(id)
|
||||
{
|
||||
@ -32,7 +34,7 @@ bool ModePageDevice::Dispatch(scsi_command cmd)
|
||||
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
|
||||
}
|
||||
|
||||
int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const
|
||||
int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int offset, int max_length) const
|
||||
{
|
||||
if (max_length < 0) {
|
||||
return 0;
|
||||
@ -77,36 +79,34 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_leng
|
||||
|
||||
// Page 0 must be last
|
||||
if (!page0.empty()) {
|
||||
size_t offset = result.size();
|
||||
|
||||
// Page data
|
||||
result.insert(result.end(), page0.begin(), page0.end());
|
||||
// Page payload size
|
||||
result[offset + 1] = (byte)(page0.size() - 2);
|
||||
result[result.size() + 1] = (byte)(page0.size() - 2);
|
||||
}
|
||||
|
||||
// Do not return more than the requested number of bytes
|
||||
size_t size = (size_t)max_length < result.size() ? max_length : result.size();
|
||||
memcpy(buf, result.data(), size);
|
||||
size_t size = min((size_t)max_length, result.size());
|
||||
memcpy(&buf.data()[offset], result.data(), size);
|
||||
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
void ModePageDevice::ModeSense6()
|
||||
{
|
||||
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
|
||||
ctrl->length = ModeSense6(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
|
||||
|
||||
EnterDataInPhase();
|
||||
}
|
||||
|
||||
void ModePageDevice::ModeSense10()
|
||||
{
|
||||
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
|
||||
ctrl->length = ModeSense10(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
|
||||
|
||||
EnterDataInPhase();
|
||||
}
|
||||
|
||||
void ModePageDevice::ModeSelect(const vector<int>&, const BYTE *, int) const
|
||||
void ModePageDevice::ModeSelect(const vector<int>&, const vector<BYTE>&, int) const
|
||||
{
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
@ -127,7 +127,7 @@ void ModePageDevice::ModeSelect10()
|
||||
|
||||
int ModePageDevice::ModeSelectCheck(int length) const
|
||||
{
|
||||
// Error if save parameters are set for other types than of SCHD, SCRM or SCMO
|
||||
// Error if save parameters are set for other types than SCHD, SCRM or SCMO
|
||||
// TODO The assumption above is not correct, and this code should be located elsewhere
|
||||
if (GetType() != "SCHD" && GetType() != "SCRM" && GetType() != "SCMO" && (ctrl->cmd[1] & 0x01)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
@ -145,12 +145,7 @@ int ModePageDevice::ModeSelectCheck6() const
|
||||
int ModePageDevice::ModeSelectCheck10() const
|
||||
{
|
||||
// Receive the data specified by the parameter length
|
||||
int length = ctrl->cmd[7];
|
||||
length <<= 8;
|
||||
length |= ctrl->cmd[8];
|
||||
if (length > ctrl->bufsize) {
|
||||
length = ctrl->bufsize;
|
||||
}
|
||||
size_t length = min(controller->GetBufferSize(), (size_t)GetInt16(ctrl->cmd, 7));
|
||||
|
||||
return ModeSelectCheck(length);
|
||||
return ModeSelectCheck((int)length);
|
||||
}
|
||||
|
@ -25,11 +25,11 @@ public:
|
||||
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
virtual void ModeSelect(const vector<int>&, const BYTE *, int) const;
|
||||
virtual void ModeSelect(const vector<int>&, const vector<BYTE>&, int) const;
|
||||
|
||||
protected:
|
||||
|
||||
int AddModePages(const vector<int>&, BYTE *, int) const;
|
||||
int AddModePages(const vector<int>&, vector<BYTE>&, int, int) const;
|
||||
virtual void SetUpModePages(map<int, vector<byte>>&, int, bool) const = 0;
|
||||
|
||||
private:
|
||||
@ -38,8 +38,8 @@ private:
|
||||
|
||||
Dispatcher<ModePageDevice> dispatcher;
|
||||
|
||||
virtual int ModeSense6(const vector<int>&, BYTE *, int) const = 0;
|
||||
virtual int ModeSense10(const vector<int>&, BYTE *, int) const = 0;
|
||||
virtual int ModeSense6(const vector<int>&, vector<BYTE>&, int) const = 0;
|
||||
virtual int ModeSense10(const vector<int>&, vector<BYTE>&, int) const = 0;
|
||||
|
||||
void ModeSense6();
|
||||
void ModeSense10();
|
||||
|
@ -9,11 +9,13 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "dispatcher.h"
|
||||
#include "primary_device.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace scsi_defs;
|
||||
using namespace scsi_command_util;
|
||||
|
||||
PrimaryDevice::PrimaryDevice(const string& id) : Device(id)
|
||||
{
|
||||
@ -53,12 +55,9 @@ void PrimaryDevice::Inquiry()
|
||||
|
||||
vector<byte> buf = InquiryInternal();
|
||||
|
||||
size_t allocation_length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
|
||||
if (allocation_length > buf.size()) {
|
||||
allocation_length = buf.size();
|
||||
}
|
||||
size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
|
||||
|
||||
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
||||
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
|
||||
ctrl->length = (uint32_t)allocation_length;
|
||||
|
||||
// Report if the device does not support the requested LUN
|
||||
@ -66,7 +65,7 @@ void PrimaryDevice::Inquiry()
|
||||
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, GetId())
|
||||
|
||||
// Signal that the requested LUN does not exist
|
||||
ctrl->buffer[0] |= 0x7f;
|
||||
controller->GetBuffer()[0] |= 0x7f;
|
||||
}
|
||||
|
||||
EnterDataInPhase();
|
||||
@ -74,18 +73,17 @@ void PrimaryDevice::Inquiry()
|
||||
|
||||
void PrimaryDevice::ReportLuns()
|
||||
{
|
||||
int allocation_length = (ctrl->cmd[6] << 24) + (ctrl->cmd[7] << 16) + (ctrl->cmd[8] << 8) + ctrl->cmd[9];
|
||||
|
||||
BYTE *buf = ctrl->buffer;
|
||||
memset(buf, 0, allocation_length < ctrl->bufsize ? allocation_length : ctrl->bufsize);
|
||||
|
||||
int size = 0;
|
||||
|
||||
// Only SELECT REPORT mode 0 is supported
|
||||
if (ctrl->cmd[2]) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
uint32_t allocation_length = GetInt32(ctrl->cmd, 6);
|
||||
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
fill_n(buf.begin(), min(controller->GetBufferSize(), (size_t)allocation_length), 0);
|
||||
|
||||
uint32_t size = 0;
|
||||
for (int lun = 0; lun < controller->GetMaxLuns(); lun++) {
|
||||
if (controller->HasDeviceForLun(lun)) {
|
||||
size += 8;
|
||||
@ -93,12 +91,11 @@ void PrimaryDevice::ReportLuns()
|
||||
}
|
||||
}
|
||||
|
||||
buf[2] = (BYTE)(size >> 8);
|
||||
buf[3] = (BYTE)size;
|
||||
SetInt16(buf, 2, size);
|
||||
|
||||
size += 8;
|
||||
|
||||
ctrl->length = allocation_length < size ? allocation_length : size;
|
||||
ctrl->length = min(allocation_length, size);
|
||||
|
||||
EnterDataInPhase();
|
||||
}
|
||||
@ -118,17 +115,14 @@ void PrimaryDevice::RequestSense()
|
||||
// Do not raise an exception here because the rest of the code must be executed
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
||||
|
||||
ctrl->status = 0x00;
|
||||
controller->SetStatus(0);
|
||||
}
|
||||
|
||||
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
|
||||
|
||||
size_t allocation_length = ctrl->cmd[4];
|
||||
if (allocation_length > buf.size()) {
|
||||
allocation_length = buf.size();
|
||||
}
|
||||
size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
|
||||
|
||||
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
||||
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
|
||||
ctrl->length = (uint32_t)allocation_length;
|
||||
|
||||
EnterDataInPhase();
|
||||
@ -201,12 +195,13 @@ vector<byte> PrimaryDevice::HandleRequestSense() const
|
||||
buf[12] = (byte)(GetStatusCode() >> 8);
|
||||
buf[13] = (byte)GetStatusCode();
|
||||
|
||||
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12])
|
||||
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, controller->GetStatus(),
|
||||
(int)buf[2], (int)buf[12])
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool PrimaryDevice::WriteByteSequence(BYTE *, uint32_t)
|
||||
bool PrimaryDevice::WriteByteSequence(vector<BYTE>&, uint32_t)
|
||||
{
|
||||
LOGERROR("%s Writing bytes is not supported by this device", __PRETTY_FUNCTION__)
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
virtual bool Dispatch(scsi_command);
|
||||
|
||||
void SetController(AbstractController *);
|
||||
virtual bool WriteByteSequence(BYTE *, uint32_t);
|
||||
virtual bool WriteByteSequence(vector<BYTE>&, uint32_t);
|
||||
virtual int GetSendDelay() const { return BUS::SEND_NO_DELAY; }
|
||||
|
||||
protected:
|
||||
|
@ -13,63 +13,61 @@
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
void scsi_command_util::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length, int sector_size)
|
||||
void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& buf, int length, int sector_size)
|
||||
{
|
||||
assert(length >= 0);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
// PF
|
||||
if (cdb[1] & 0x10) {
|
||||
bool has_valid_page_code = false;
|
||||
if (!(cdb[1] & 0x10)) {
|
||||
// Vendor-specific parameters (SCSI-1) are not supported
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
// Mode Parameter header
|
||||
if (length >= 12) {
|
||||
// Check the block length
|
||||
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) ||
|
||||
buf[11] != (BYTE)sector_size) {
|
||||
// See below for details
|
||||
bool has_valid_page_code = false;
|
||||
|
||||
// Mode Parameter header
|
||||
int offset = 0;
|
||||
if (length >= 12) {
|
||||
// Check the block length
|
||||
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) ||
|
||||
buf[11] != (BYTE)sector_size) {
|
||||
// See below for details
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
offset += 12;
|
||||
length -= 12;
|
||||
}
|
||||
|
||||
// Parsing the page
|
||||
// TODO The length handling is wrong in case of length < size
|
||||
while (length > 0) {
|
||||
// Format device page
|
||||
if (int page = buf[offset]; page == 0x03) {
|
||||
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
|
||||
// drives support this, e.g FUJITSU M2624S
|
||||
// We are fine as long as the current sector size remains unchanged
|
||||
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
|
||||
// With rascsi it is not possible to permanently (by formatting) change the sector size,
|
||||
// because the size is an externally configurable setting only
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
offset += 12;
|
||||
length -= 12;
|
||||
has_valid_page_code = true;
|
||||
}
|
||||
else {
|
||||
LOGWARN("Unknown MODE SELECT page code: $%02X", page)
|
||||
}
|
||||
|
||||
// Parsing the page
|
||||
// TODO The length handling is wrong in case of length < size
|
||||
while (length > 0) {
|
||||
// Format device page
|
||||
if (int page = buf[offset]; page == 0x03) {
|
||||
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
|
||||
// drives support this, e.g FUJITSU M2624S
|
||||
// We are fine as long as the current sector size remains unchanged
|
||||
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
|
||||
// With rascsi it is not possible to permanently (by formatting) change the sector size,
|
||||
// because the size is an externally configurable setting only
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
has_valid_page_code = true;
|
||||
}
|
||||
else {
|
||||
LOGWARN("Unknown MODE SELECT page code: $%02X", page)
|
||||
}
|
||||
|
||||
// Advance to the next page
|
||||
int size = buf[offset + 1] + 2;
|
||||
length -= size;
|
||||
offset += size;
|
||||
}
|
||||
|
||||
if (!has_valid_page_code) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
// Advance to the next page
|
||||
int size = buf[offset + 1] + 2;
|
||||
length -= size;
|
||||
offset += size;
|
||||
}
|
||||
else {
|
||||
// Vendor-specific parameters (SCSI-1) are not supported
|
||||
|
||||
if (!has_valid_page_code) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
}
|
||||
@ -105,6 +103,11 @@ int scsi_command_util::GetInt16(const vector<int>& buf, int offset)
|
||||
return (buf[offset] << 8) | buf[offset + 1];
|
||||
}
|
||||
|
||||
int scsi_command_util::GetInt24(const vector<int>& buf, int offset)
|
||||
{
|
||||
return (buf[offset] << 16) | (buf[offset + 1] << 8) | buf[offset + 2];
|
||||
}
|
||||
|
||||
uint32_t scsi_command_util::GetInt32(const vector<int>& buf, int offset)
|
||||
{
|
||||
return ((uint32_t)buf[offset] << 24) | ((uint32_t)buf[offset + 1] << 16) |
|
||||
@ -119,42 +122,42 @@ uint64_t scsi_command_util::GetInt64(const vector<int>& buf, int offset)
|
||||
((uint64_t)buf[offset + 6] << 8) | (uint64_t)buf[offset + 7];
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt16(BYTE *buf, int value)
|
||||
{
|
||||
buf[0] = (BYTE)(value >> 8);
|
||||
buf[1] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt32(BYTE *buf, uint32_t value)
|
||||
{
|
||||
buf[0] = (BYTE)(value >> 24);
|
||||
buf[1] = (BYTE)(value >> 16);
|
||||
buf[2] = (BYTE)(value >> 8);
|
||||
buf[3] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt64(BYTE *buf, uint64_t value)
|
||||
{
|
||||
buf[0] = (BYTE)(value >> 56);
|
||||
buf[1] = (BYTE)(value >> 48);
|
||||
buf[2] = (BYTE)(value >> 40);
|
||||
buf[3] = (BYTE)(value >> 32);
|
||||
buf[4] = (BYTE)(value >> 24);
|
||||
buf[5] = (BYTE)(value >> 16);
|
||||
buf[6] = (BYTE)(value >> 8);
|
||||
buf[7] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt16(vector<byte>& buf, int offset, int value)
|
||||
{
|
||||
buf[offset] = (byte)(value >> 8);
|
||||
buf[offset + 1] = (byte)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt32(vector<byte>& buf, int offset, int value)
|
||||
void scsi_command_util::SetInt32(vector<byte>& buf, int offset, uint32_t value)
|
||||
{
|
||||
buf[offset] = (byte)(value >> 24);
|
||||
buf[offset + 1] = (byte)(value >> 16);
|
||||
buf[offset + 2] = (byte)(value >> 8);
|
||||
buf[offset + 3] = (byte)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt16(vector<BYTE>& buf, int offset, int value)
|
||||
{
|
||||
buf[offset] = (BYTE)(value >> 8);
|
||||
buf[offset + 1] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt32(vector<BYTE>& buf, int offset, uint32_t value)
|
||||
{
|
||||
buf[offset] = (BYTE)(value >> 24);
|
||||
buf[offset + 1] = (BYTE)(value >> 16);
|
||||
buf[offset + 2] = (BYTE)(value >> 8);
|
||||
buf[offset + 3] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt64(vector<BYTE>& buf, int offset, uint64_t value)
|
||||
{
|
||||
buf[offset] = (BYTE)(value >> 56);
|
||||
buf[offset + 1] = (BYTE)(value >> 48);
|
||||
buf[offset + 2] = (BYTE)(value >> 40);
|
||||
buf[offset + 3] = (BYTE)(value >> 32);
|
||||
buf[offset + 4] = (BYTE)(value >> 24);
|
||||
buf[offset + 5] = (BYTE)(value >> 16);
|
||||
buf[offset + 6] = (BYTE)(value >> 8);
|
||||
buf[offset + 7] = (BYTE)value;
|
||||
}
|
||||
|
@ -18,16 +18,17 @@ using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
namespace scsi_command_util
|
||||
{
|
||||
void ModeSelect(const vector<int>&, const BYTE *, int, int);
|
||||
void ModeSelect(const vector<int>&, const vector<BYTE>&, int, int);
|
||||
void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
|
||||
void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
|
||||
|
||||
int GetInt16(const vector<int>&, int);
|
||||
int GetInt24(const vector<int>&, int);
|
||||
uint32_t GetInt32(const vector<int>&, int);
|
||||
uint64_t GetInt64(const vector<int>&, int);
|
||||
void SetInt16(BYTE *, int);
|
||||
void SetInt32(BYTE *, uint32_t);
|
||||
void SetInt64(BYTE *, uint64_t);
|
||||
void SetInt16(vector<byte>&, int, int);
|
||||
void SetInt32(vector<byte>&, int, int);
|
||||
void SetInt32(vector<byte>&, int, uint32_t);
|
||||
void SetInt16(vector<BYTE>&, int, int);
|
||||
void SetInt32(vector<BYTE>&, int, uint32_t);
|
||||
void SetInt64(vector<BYTE>&, int, uint64_t);
|
||||
}
|
||||
|
@ -79,20 +79,6 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
|
||||
SetReady(true);
|
||||
SetReset(false);
|
||||
|
||||
// if (m_bTapEnable) {
|
||||
// tap->GetMacAddr(m_mac_addr);
|
||||
// m_mac_addr[5]++;
|
||||
// }
|
||||
|
||||
// !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development!
|
||||
// TODO: Remove this hard-coded address
|
||||
m_mac_addr[0] = (byte)0x00;
|
||||
m_mac_addr[1] = (byte)0x80;
|
||||
m_mac_addr[2] = (byte)0x19;
|
||||
m_mac_addr[3] = (byte)0x10;
|
||||
m_mac_addr[4] = (byte)0x98;
|
||||
m_mac_addr[5] = (byte)0xE3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -144,10 +130,10 @@ vector<byte> SCSIDaynaPort::InquiryInternal() const
|
||||
// - The SCSI/Link apparently has about 6KB buffer space for packets.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
int rx_packet_size = 0;
|
||||
auto response = (scsi_resp_read_t*)buf;
|
||||
auto response = (scsi_resp_read_t*)buf.data();
|
||||
|
||||
int requested_length = cdb[4];
|
||||
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length)
|
||||
@ -246,8 +232,8 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
// breaks because of this, the work-around has to be re-evaluated.
|
||||
size = 64;
|
||||
}
|
||||
SetInt16(&buf[0], size);
|
||||
SetInt32(&buf[2], m_tap.PendingPackets() ? 0x10 : 0x00);
|
||||
SetInt16(buf, 0, size);
|
||||
SetInt32(buf, 2, m_tap.PendingPackets() ? 0x10 : 0x00);
|
||||
|
||||
// Return the packet size + 2 for the length + 4 for the flag field
|
||||
// The CRC was already appended by the ctapdriver
|
||||
@ -291,19 +277,19 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
|
||||
// XX XX ... is the actual packet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t)
|
||||
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
int data_format = cdb[5];
|
||||
int data_length = cdb[4] + (cdb[3] << 8);
|
||||
int data_length = GetInt16(cdb, 3);
|
||||
|
||||
if (data_format == 0x00){
|
||||
m_tap.Send(buf, data_length);
|
||||
m_tap.Send(buf.data(), data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else if (data_format == 0x80){
|
||||
// The data length is specified in the first 2 bytes of the payload
|
||||
data_length=buf[1] + (buf[0] << 8);
|
||||
m_tap.Send(&buf[4], data_length);
|
||||
m_tap.Send(&(buf.data()[4]), data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else
|
||||
@ -331,33 +317,11 @@ bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t
|
||||
// - long #3: frames lost
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, BYTE *buffer) const
|
||||
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
{
|
||||
int allocation_length = cdb[4] + (cdb[3] << 8);
|
||||
memcpy(buf.data(), &m_scsi_link_stats, sizeof(m_scsi_link_stats));
|
||||
|
||||
// memset(buffer,0,18);
|
||||
// memcpy(&buffer[0],m_mac_addr,sizeof(m_mac_addr));
|
||||
// uint32_t frame_alignment_errors;
|
||||
// uint32_t crc_errors;
|
||||
// uint32_t frames_lost;
|
||||
// // frame alignment errors
|
||||
// frame_alignment_errors = htonl(0);
|
||||
// memcpy(&(buffer[6]),&frame_alignment_errors,sizeof(frame_alignment_errors));
|
||||
// // CRC errors
|
||||
// crc_errors = htonl(0);
|
||||
// memcpy(&(buffer[10]),&crc_errors,sizeof(crc_errors));
|
||||
// // frames lost
|
||||
// frames_lost = htonl(0);
|
||||
// memcpy(&(buffer[14]),&frames_lost,sizeof(frames_lost));
|
||||
|
||||
int response_size = sizeof(m_scsi_link_stats);
|
||||
memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats));
|
||||
|
||||
if (response_size > allocation_length) {
|
||||
response_size = allocation_length;
|
||||
}
|
||||
|
||||
return response_size;
|
||||
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 4));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -407,11 +371,7 @@ void SCSIDaynaPort::TestUnitReady()
|
||||
void SCSIDaynaPort::Read6()
|
||||
{
|
||||
// Get record number and block number
|
||||
uint32_t record = ctrl->cmd[1] & 0x1f;
|
||||
record <<= 8;
|
||||
record |= ctrl->cmd[2];
|
||||
record <<= 8;
|
||||
record |= ctrl->cmd[3];
|
||||
uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
|
||||
ctrl->blocks=1;
|
||||
|
||||
// If any commands have a bogus control value, they were probably not
|
||||
@ -423,7 +383,7 @@ void SCSIDaynaPort::Read6()
|
||||
|
||||
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
|
||||
|
||||
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
|
||||
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), record);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
|
||||
|
||||
// Set next block
|
||||
@ -434,20 +394,16 @@ void SCSIDaynaPort::Read6()
|
||||
|
||||
void SCSIDaynaPort::Write6()
|
||||
{
|
||||
// Reallocate buffer (because it is not transfer for each block)
|
||||
if (ctrl->bufsize < DAYNAPORT_BUFFER_SIZE) {
|
||||
delete[] ctrl->buffer;
|
||||
ctrl->buffer = new BYTE[ctrl->bufsize];
|
||||
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
|
||||
}
|
||||
// Ensure a sufficient buffer size (because it is not transfer for each block)
|
||||
controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
|
||||
|
||||
int data_format = ctrl->cmd[5];
|
||||
|
||||
if(data_format == 0x00) {
|
||||
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
|
||||
if (data_format == 0x00) {
|
||||
ctrl->length = GetInt16(ctrl->cmd, 3);
|
||||
}
|
||||
else if (data_format == 0x80) {
|
||||
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8) + 8;
|
||||
ctrl->length = GetInt16(ctrl->cmd, 3 + 8);
|
||||
}
|
||||
else {
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
|
||||
@ -467,7 +423,7 @@ void SCSIDaynaPort::Write6()
|
||||
|
||||
void SCSIDaynaPort::RetrieveStatistics()
|
||||
{
|
||||
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
|
||||
ctrl->length = RetrieveStats(ctrl->cmd, controller->GetBuffer());
|
||||
|
||||
// Set next block
|
||||
ctrl->blocks = 1;
|
||||
@ -506,7 +462,7 @@ void SCSIDaynaPort::SetInterfaceMode()
|
||||
{
|
||||
// Check whether this command is telling us to "Set Interface Mode" or "Set MAC Address"
|
||||
|
||||
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
|
||||
ctrl->length = RetrieveStats(ctrl->cmd, controller->GetBuffer());
|
||||
switch(ctrl->cmd[5]){
|
||||
case CMD_SCSILINK_SETMODE:
|
||||
// TODO Not implemented, do nothing
|
||||
|
@ -24,8 +24,9 @@
|
||||
// This does NOT include the file system functionality that is present
|
||||
// in the Sharp X68000 host bridge.
|
||||
//
|
||||
// Note: This requires the DaynaPort SCSI Link driver.
|
||||
// Note: This requires a DaynaPort SCSI Link driver.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "os.h"
|
||||
@ -42,8 +43,8 @@
|
||||
//===========================================================================
|
||||
class SCSIDaynaPort final : public Disk
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
SCSIDaynaPort();
|
||||
~SCSIDaynaPort() override = default;
|
||||
SCSIDaynaPort(SCSIDaynaPort&) = delete;
|
||||
@ -54,15 +55,13 @@ public:
|
||||
|
||||
// Commands
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int Read(const vector<int>&, BYTE *, uint64_t) override;
|
||||
bool WriteBytes(const vector<int>&, const BYTE *, uint64_t);
|
||||
int Read(const vector<int>&, vector<BYTE>&, uint64_t) override;
|
||||
bool WriteBytes(const vector<int>&, const vector<BYTE>&, uint64_t);
|
||||
int WriteCheck(uint64_t block) override;
|
||||
|
||||
int RetrieveStats(const vector<int>&, BYTE *) const;
|
||||
int RetrieveStats(const vector<int>&, vector<BYTE>&) const;
|
||||
bool EnableInterface(const vector<int>&);
|
||||
|
||||
void SetMacAddr(const vector<int>&, BYTE *); // Set MAC address
|
||||
|
||||
void TestUnitReady() override;
|
||||
void Read6() override;
|
||||
void Write6() override;
|
||||
@ -108,19 +107,19 @@ private:
|
||||
uint32_t length;
|
||||
read_data_flags_t flags;
|
||||
byte pad;
|
||||
byte data[ETH_FRAME_LEN + sizeof(uint32_t)]; // Frame length + 4 byte CRC
|
||||
array<byte, ETH_FRAME_LEN + sizeof(uint32_t)> data; // Frame length + 4 byte CRC
|
||||
};
|
||||
|
||||
using scsi_resp_link_stats_t = struct __attribute__((packed)) {
|
||||
byte mac_address[6];
|
||||
array<byte, 6> mac_address;
|
||||
uint32_t frame_alignment_errors;
|
||||
uint32_t crc_errors;
|
||||
uint32_t frames_lost;
|
||||
};
|
||||
|
||||
scsi_resp_link_stats_t m_scsi_link_stats = {
|
||||
//MAC address of @PotatoFi's DayanPort
|
||||
.mac_address = { byte{0x00}, byte{0x80}, byte{0x19}, byte{0x10}, byte{0x98}, byte{0xE3} },
|
||||
// TODO Remove this hard-coded MAC address, see https://github.com/akuker/RASCSI/issues/598
|
||||
.mac_address = { byte{0x00}, byte{0x80}, byte{0x19}, byte{0x10}, byte{0x98}, byte{0xe3} },
|
||||
.frame_alignment_errors = 0,
|
||||
.crc_errors = 0,
|
||||
.frames_lost = 0,
|
||||
@ -130,6 +129,4 @@ private:
|
||||
|
||||
// TAP valid flag
|
||||
bool m_bTapEnable = false;
|
||||
|
||||
array<byte, 6> m_mac_addr;
|
||||
};
|
||||
|
@ -37,12 +37,6 @@ SCSIBR::SCSIBR() : Disk("SCBR")
|
||||
dispatcher.Add(scsi_command::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
|
||||
}
|
||||
|
||||
SCSIBR::~SCSIBR()
|
||||
{
|
||||
// Release host file system
|
||||
fs.Reset();
|
||||
}
|
||||
|
||||
bool SCSIBR::Init(const unordered_map<string, string>& params)
|
||||
{
|
||||
SetParams(params);
|
||||
@ -54,17 +48,16 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
|
||||
LOGERROR("Unable to open the TAP interface")
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Generate MAC Address
|
||||
memset(mac_addr, 0x00, 6);
|
||||
if (m_bTapEnable) {
|
||||
tap.GetMacAddr(mac_addr);
|
||||
tap.GetMacAddr(mac_addr.data());
|
||||
mac_addr[5]++;
|
||||
}
|
||||
|
||||
// Packet reception flag OFF
|
||||
packet_enable = false;
|
||||
#endif
|
||||
|
||||
SetReady(m_bTapEnable);
|
||||
|
||||
@ -84,11 +77,10 @@ bool SCSIBR::Dispatch(scsi_command cmd)
|
||||
|
||||
vector<byte> SCSIBR::InquiryInternal() const
|
||||
{
|
||||
vector<byte> b = HandleInquiry(device_type::COMMUNICATIONS, scsi_level::SCSI_2, false);
|
||||
vector<byte> buf = HandleInquiry(device_type::COMMUNICATIONS, scsi_level::SCSI_2, false);
|
||||
|
||||
// The bridge returns 6 more additional bytes than the other devices
|
||||
auto buf = vector<byte>(0x1F + 8 + 5);
|
||||
memcpy(buf.data(), b.data(), b.size());
|
||||
// The bridge returns more additional bytes than the other devices
|
||||
buf.resize(0x1F + 8 + 5);
|
||||
|
||||
buf[4] = byte{0x1F + 8};
|
||||
|
||||
@ -112,7 +104,7 @@ void SCSIBR::TestUnitReady()
|
||||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
|
||||
int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
@ -138,18 +130,18 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
|
||||
if (phase == 0) {
|
||||
// Get packet size
|
||||
ReceivePacket();
|
||||
SetInt16(&buf[0], packet_len);
|
||||
SetInt16(buf, 0, packet_len);
|
||||
return 2;
|
||||
} else {
|
||||
// Get package data
|
||||
GetPacketBuf(buf);
|
||||
GetPacketBuf(buf, 0);
|
||||
return packet_len;
|
||||
}
|
||||
|
||||
case 2: // Received packet acquisition (size + buffer simultaneously)
|
||||
ReceivePacket();
|
||||
SetInt16(&buf[0], packet_len);
|
||||
GetPacketBuf(&buf[2]);
|
||||
SetInt16(buf, 0, packet_len);
|
||||
GetPacketBuf(buf, 2);
|
||||
return packet_len + 2;
|
||||
|
||||
case 3: {
|
||||
@ -159,14 +151,11 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
|
||||
int total_len = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ReceivePacket();
|
||||
SetInt16(&buf[0], packet_len);
|
||||
// TODO Callee should not modify buffer pointer
|
||||
buf += 2;
|
||||
SetInt16(buf, total_len, packet_len);
|
||||
total_len += 2;
|
||||
if (packet_len == 0)
|
||||
break;
|
||||
GetPacketBuf(buf);
|
||||
buf += packet_len;
|
||||
GetPacketBuf(buf, 0);
|
||||
total_len += packet_len;
|
||||
}
|
||||
return total_len;
|
||||
@ -203,7 +192,7 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
bool SCSIBR::WriteBytes(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
@ -215,11 +204,7 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
int phase = cdb[9];
|
||||
|
||||
// Get the number of lights
|
||||
int len = cdb[6];
|
||||
len <<= 8;
|
||||
len |= cdb[7];
|
||||
len <<= 8;
|
||||
len |= cdb[8];
|
||||
int len = GetInt24(cdb, 6);
|
||||
|
||||
switch (type) {
|
||||
case 1: // Ethernet
|
||||
@ -229,11 +214,11 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
}
|
||||
|
||||
switch (func) {
|
||||
case 0: // MAC address setting
|
||||
case 0:
|
||||
SetMacAddr(buf);
|
||||
return true;
|
||||
|
||||
case 1: // Send packet
|
||||
case 1:
|
||||
SendPacket(buf, len);
|
||||
return true;
|
||||
|
||||
@ -267,14 +252,10 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
|
||||
|
||||
void SCSIBR::GetMessage10()
|
||||
{
|
||||
// Reallocate buffer (because it is not transfer for each block)
|
||||
if (ctrl->bufsize < 0x1000000) {
|
||||
delete[] ctrl->buffer;
|
||||
ctrl->bufsize = 0x1000000;
|
||||
ctrl->buffer = new BYTE[ctrl->bufsize];
|
||||
}
|
||||
// Ensure a sufficient buffer size (because it is not a transfer for each block)
|
||||
controller->AllocateBuffer(0x1000000);
|
||||
|
||||
ctrl->length = GetMessage10(ctrl->cmd, ctrl->buffer);
|
||||
ctrl->length = GetMessage10(ctrl->cmd, controller->GetBuffer());
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
}
|
||||
@ -295,24 +276,14 @@ void SCSIBR::GetMessage10()
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::SendMessage10()
|
||||
{
|
||||
// Reallocate buffer (because it is not transfer for each block)
|
||||
if (ctrl->bufsize < 0x1000000) {
|
||||
delete[] ctrl->buffer;
|
||||
ctrl->bufsize = 0x1000000;
|
||||
ctrl->buffer = new BYTE[ctrl->bufsize];
|
||||
}
|
||||
|
||||
// Set transfer amount
|
||||
ctrl->length = ctrl->cmd[6];
|
||||
ctrl->length <<= 8;
|
||||
ctrl->length |= ctrl->cmd[7];
|
||||
ctrl->length <<= 8;
|
||||
ctrl->length |= ctrl->cmd[8];
|
||||
|
||||
ctrl->length = GetInt24(ctrl->cmd, 6);
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
}
|
||||
|
||||
// Ensure a sufficient buffer size (because it is not a transfer for each block)
|
||||
controller->AllocateBuffer(0x1000000);
|
||||
|
||||
// Set next block
|
||||
ctrl->blocks = 1;
|
||||
ctrl->next = 1;
|
||||
@ -320,39 +291,36 @@ void SCSIBR::SendMessage10()
|
||||
EnterDataOutPhase();
|
||||
}
|
||||
|
||||
int SCSIBR::GetMacAddr(BYTE *mac) const
|
||||
int SCSIBR::GetMacAddr(vector<BYTE>& mac) const
|
||||
{
|
||||
memcpy(mac, mac_addr, 6);
|
||||
return 6;
|
||||
memcpy(mac.data(), mac_addr.data(), mac_addr.size());
|
||||
return (int)mac_addr.size();
|
||||
}
|
||||
|
||||
void SCSIBR::SetMacAddr(const BYTE *mac)
|
||||
void SCSIBR::SetMacAddr(const vector<BYTE>& mac)
|
||||
{
|
||||
memcpy(mac_addr, mac, 6);
|
||||
memcpy(mac_addr.data(), mac.data(), mac_addr.size());
|
||||
}
|
||||
|
||||
void SCSIBR::ReceivePacket()
|
||||
{
|
||||
static const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
// previous packet has not been received
|
||||
if (packet_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Receive packet
|
||||
packet_len = tap.Receive(packet_buf);
|
||||
packet_len = tap.Receive(packet_buf.data());
|
||||
|
||||
// Check if received packet
|
||||
if (memcmp(packet_buf, mac_addr, 6) != 0 && memcmp(packet_buf, bcast_addr.data(), bcast_addr.size()) != 0) {
|
||||
if (memcmp(packet_buf.data(), mac_addr.data(), mac_addr.size()) != 0
|
||||
&& memcmp(packet_buf.data(), bcast_addr.data(), bcast_addr.size()) != 0) {
|
||||
packet_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Discard if it exceeds the buffer size
|
||||
if (packet_len > 2048) {
|
||||
packet_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Store in receive buffer
|
||||
@ -361,7 +329,7 @@ void SCSIBR::ReceivePacket()
|
||||
}
|
||||
}
|
||||
|
||||
void SCSIBR::GetPacketBuf(BYTE *buf)
|
||||
void SCSIBR::GetPacketBuf(vector<BYTE>& buf, int index)
|
||||
{
|
||||
// Size limit
|
||||
int len = packet_len;
|
||||
@ -370,15 +338,15 @@ void SCSIBR::GetPacketBuf(BYTE *buf)
|
||||
}
|
||||
|
||||
// Copy
|
||||
memcpy(buf, packet_buf, len);
|
||||
memcpy(buf.data() + index, packet_buf.data(), len);
|
||||
|
||||
// Received
|
||||
packet_enable = false;
|
||||
}
|
||||
|
||||
void SCSIBR::SendPacket(const BYTE *buf, int len)
|
||||
void SCSIBR::SendPacket(const vector<BYTE>& buf, int len)
|
||||
{
|
||||
tap.Send(buf, len);
|
||||
tap.Send(buf.data(), len);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -386,10 +354,10 @@ void SCSIBR::SendPacket(const BYTE *buf, int len)
|
||||
// $40 - Device Boot
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_InitDevice(BYTE *buf)
|
||||
void SCSIBR::FS_InitDevice(vector<BYTE>& buf)
|
||||
{
|
||||
fs.Reset();
|
||||
fsresult = fs.InitDevice((Human68k::argument_t*)buf);
|
||||
fsresult = fs.InitDevice((Human68k::argument_t*)buf.data());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -397,13 +365,13 @@ void SCSIBR::FS_InitDevice(BYTE *buf)
|
||||
// $41 - Directory Check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_CheckDir(BYTE *buf)
|
||||
void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.CheckDir(nUnit, pNamests);
|
||||
}
|
||||
@ -413,13 +381,13 @@ void SCSIBR::FS_CheckDir(BYTE *buf)
|
||||
// $42 - Create Directory
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_MakeDir(BYTE *buf)
|
||||
void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.MakeDir(nUnit, pNamests);
|
||||
}
|
||||
@ -429,13 +397,13 @@ void SCSIBR::FS_MakeDir(BYTE *buf)
|
||||
// $43 - Remove Directory
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_RemoveDir(BYTE *buf)
|
||||
void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.RemoveDir(nUnit, pNamests);
|
||||
}
|
||||
@ -445,16 +413,16 @@ void SCSIBR::FS_RemoveDir(BYTE *buf)
|
||||
// $44 - Rename
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Rename(BYTE *buf)
|
||||
void SCSIBR::FS_Rename(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::namests_t);
|
||||
|
||||
const Human68k::namests_t *pNamestsNew = (Human68k::namests_t*)&buf[i];
|
||||
const Human68k::namests_t *pNamestsNew = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.Rename(nUnit, pNamests, pNamestsNew);
|
||||
}
|
||||
@ -464,13 +432,13 @@ void SCSIBR::FS_Rename(BYTE *buf)
|
||||
// $45 - Delete File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Delete(BYTE *buf)
|
||||
void SCSIBR::FS_Delete(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto *pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto *pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.Delete(nUnit, pNamests);
|
||||
}
|
||||
@ -480,17 +448,17 @@ void SCSIBR::FS_Delete(BYTE *buf)
|
||||
// $46 - Get / Set file attributes
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Attribute(BYTE *buf)
|
||||
void SCSIBR::FS_Attribute(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::namests_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nHumanAttribute = ntohl(*dp);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nHumanAttribute = ntohl(*dp);
|
||||
|
||||
fsresult = fs.Attribute(nUnit, pNamests, nHumanAttribute);
|
||||
}
|
||||
@ -500,20 +468,20 @@ void SCSIBR::FS_Attribute(BYTE *buf)
|
||||
// $47 - File Search
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Files(BYTE *buf)
|
||||
void SCSIBR::FS_Files(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::namests_t);
|
||||
|
||||
auto files = (Human68k::files_t*)&buf[i];
|
||||
auto files = (Human68k::files_t*)&(buf.data()[i]);
|
||||
|
||||
files->sector = ntohl(files->sector);
|
||||
files->offset = ntohs(files->offset);
|
||||
@ -541,17 +509,17 @@ void SCSIBR::FS_Files(BYTE *buf)
|
||||
// $48 - File next search
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_NFiles(BYTE *buf)
|
||||
void SCSIBR::FS_NFiles(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto files = (Human68k::files_t*)&buf[i];
|
||||
auto files = (Human68k::files_t*)&(buf.data()[i]);
|
||||
|
||||
files->sector = ntohl(files->sector);
|
||||
files->offset = ntohs(files->offset);
|
||||
@ -579,28 +547,28 @@ void SCSIBR::FS_NFiles(BYTE *buf)
|
||||
// $49 - File Creation
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Create(BYTE *buf)
|
||||
void SCSIBR::FS_Create(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::namests_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nAttribute = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nAttribute = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto bp = (int*)&buf[i];
|
||||
DWORD bForce = ntohl(*bp);
|
||||
auto bp = (int*)&(buf.data()[i]);
|
||||
uint32_t bForce = ntohl(*bp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -628,20 +596,20 @@ void SCSIBR::FS_Create(BYTE *buf)
|
||||
// $4A - Open File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Open(BYTE *buf)
|
||||
void SCSIBR::FS_Open(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&buf[i];
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::namests_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -669,17 +637,17 @@ void SCSIBR::FS_Open(BYTE *buf)
|
||||
// $4B - Close File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Close(BYTE *buf)
|
||||
void SCSIBR::FS_Close(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -707,17 +675,17 @@ void SCSIBR::FS_Close(BYTE *buf)
|
||||
// $4C - Read File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Read(BYTE *buf)
|
||||
void SCSIBR::FS_Read(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nKey = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nSize = ntohl(*dp);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSize = ntohl(*dp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -725,7 +693,7 @@ void SCSIBR::FS_Read(BYTE *buf)
|
||||
pFcb->date = ntohs(pFcb->date);
|
||||
pFcb->size = ntohl(pFcb->size);
|
||||
|
||||
fsresult = fs.Read(nKey, pFcb, fsopt, nSize);
|
||||
fsresult = fs.Read(nKey, pFcb, fsopt.data(), nSize);
|
||||
|
||||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||||
pFcb->mode = htons(pFcb->mode);
|
||||
@ -747,17 +715,17 @@ void SCSIBR::FS_Read(BYTE *buf)
|
||||
// $4D - Write file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Write(BYTE *buf)
|
||||
void SCSIBR::FS_Write(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nKey = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nSize = ntohl(*dp);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSize = ntohl(*dp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -765,7 +733,7 @@ void SCSIBR::FS_Write(BYTE *buf)
|
||||
pFcb->date = ntohs(pFcb->date);
|
||||
pFcb->size = ntohl(pFcb->size);
|
||||
|
||||
fsresult = fs.Write(nKey, pFcb, fsopt, nSize);
|
||||
fsresult = fs.Write(nKey, pFcb, fsopt.data(), nSize);
|
||||
|
||||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||||
pFcb->mode = htons(pFcb->mode);
|
||||
@ -785,20 +753,20 @@ void SCSIBR::FS_Write(BYTE *buf)
|
||||
// $4E - Seek file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Seek(BYTE *buf)
|
||||
void SCSIBR::FS_Seek(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nKey = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nMode = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nMode = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto ip = (const int*)&buf[i];
|
||||
auto ip = (const int*)&(buf.data()[i]);
|
||||
int nOffset = ntohl(*ip);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
@ -827,21 +795,21 @@ void SCSIBR::FS_Seek(BYTE *buf)
|
||||
// $4F - File Timestamp Get / Set
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_TimeStamp(BYTE *buf)
|
||||
void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nKey = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&buf[i];
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nHumanTime = ntohl(*dp);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nHumanTime = ntohl(*dp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -869,10 +837,10 @@ void SCSIBR::FS_TimeStamp(BYTE *buf)
|
||||
// $50 - Get Capacity
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_GetCapacity(BYTE *buf)
|
||||
void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
Human68k::capacity_t cap;
|
||||
fsresult = fs.GetCapacity(nUnit, &cap);
|
||||
@ -882,7 +850,7 @@ void SCSIBR::FS_GetCapacity(BYTE *buf)
|
||||
cap.sectors = htons(cap.sectors);
|
||||
cap.bytes = htons(cap.bytes);
|
||||
|
||||
memcpy(fsout, &cap, sizeof(Human68k::capacity_t));
|
||||
memcpy(fsout.data(), &cap, sizeof(Human68k::capacity_t));
|
||||
fsoutlen = sizeof(Human68k::capacity_t);
|
||||
}
|
||||
|
||||
@ -891,17 +859,17 @@ void SCSIBR::FS_GetCapacity(BYTE *buf)
|
||||
// $51 - Drive status inspection/control
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_CtrlDrive(BYTE *buf)
|
||||
void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pCtrlDrive = (Human68k::ctrldrive_t*)&buf[i];
|
||||
auto pCtrlDrive = (Human68k::ctrldrive_t*)&(buf.data()[i]);
|
||||
|
||||
fsresult = fs.CtrlDrive(nUnit, pCtrlDrive);
|
||||
|
||||
memcpy(fsout, pCtrlDrive, sizeof(Human68k::ctrldrive_t));
|
||||
memcpy(fsout.data(), pCtrlDrive, sizeof(Human68k::ctrldrive_t));
|
||||
fsoutlen = sizeof(Human68k::ctrldrive_t);
|
||||
}
|
||||
|
||||
@ -910,10 +878,10 @@ void SCSIBR::FS_CtrlDrive(BYTE *buf)
|
||||
// $52 - Get DPB
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_GetDPB(BYTE *buf)
|
||||
void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
Human68k::dpb_t dpb;
|
||||
fsresult = fs.GetDPB(nUnit, &dpb);
|
||||
@ -925,7 +893,7 @@ void SCSIBR::FS_GetDPB(BYTE *buf)
|
||||
dpb.cluster_max = htons(dpb.cluster_max);
|
||||
dpb.root_sector = htons(dpb.root_sector);
|
||||
|
||||
memcpy(fsout, &dpb, sizeof(Human68k::dpb_t));
|
||||
memcpy(fsout.data(), &dpb, sizeof(Human68k::dpb_t));
|
||||
fsoutlen = sizeof(Human68k::dpb_t);
|
||||
}
|
||||
|
||||
@ -934,20 +902,20 @@ void SCSIBR::FS_GetDPB(BYTE *buf)
|
||||
// $53 - Read Sector
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_DiskRead(BYTE *buf)
|
||||
void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nSector = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSector = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nSize = ntohl(*dp);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSize = ntohl(*dp);
|
||||
|
||||
fsresult = fs.DiskRead(nUnit, fsout, nSector, nSize);
|
||||
fsresult = fs.DiskRead(nUnit, fsout.data(), nSector, nSize);
|
||||
fsoutlen = 0x200;
|
||||
}
|
||||
|
||||
@ -956,10 +924,10 @@ void SCSIBR::FS_DiskRead(BYTE *buf)
|
||||
// $54 - Write Sector
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_DiskWrite(BYTE *buf)
|
||||
void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.DiskWrite(nUnit);
|
||||
}
|
||||
@ -969,17 +937,17 @@ void SCSIBR::FS_DiskWrite(BYTE *buf)
|
||||
// $55 - IOCTRL
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Ioctrl(BYTE *buf)
|
||||
void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
int i = sizeof(DWORD);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (DWORD*)&buf[i];
|
||||
DWORD nFunction = ntohl(*dp);
|
||||
i += sizeof(DWORD);
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nFunction = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pIoctrl = (Human68k::ioctrl_t*)&buf[i];
|
||||
auto pIoctrl = (Human68k::ioctrl_t*)&(buf.data()[i]);
|
||||
|
||||
switch (nFunction) {
|
||||
case 2:
|
||||
@ -1015,10 +983,10 @@ void SCSIBR::FS_Ioctrl(BYTE *buf)
|
||||
// $56 - Flush
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Flush(BYTE *buf)
|
||||
void SCSIBR::FS_Flush(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.Flush(nUnit);
|
||||
}
|
||||
@ -1028,10 +996,10 @@ void SCSIBR::FS_Flush(BYTE *buf)
|
||||
// $57 - Check Media
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_CheckMedia(BYTE *buf)
|
||||
void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.CheckMedia(nUnit);
|
||||
}
|
||||
@ -1041,10 +1009,10 @@ void SCSIBR::FS_CheckMedia(BYTE *buf)
|
||||
// $58 - Lock
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::FS_Lock(BYTE *buf)
|
||||
void SCSIBR::FS_Lock(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
DWORD nUnit = ntohl(*dp);
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.Lock(nUnit);
|
||||
}
|
||||
@ -1054,11 +1022,11 @@ void SCSIBR::FS_Lock(BYTE *buf)
|
||||
// Read Filesystem (result code)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIBR::ReadFsResult(BYTE *buf) const
|
||||
int SCSIBR::ReadFsResult(vector<BYTE>& buf) const
|
||||
{
|
||||
auto dp = (DWORD*)buf;
|
||||
auto dp = (uint32_t *)buf.data();
|
||||
*dp = htonl(fsresult);
|
||||
return sizeof(DWORD);
|
||||
return sizeof(uint32_t);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -1066,9 +1034,9 @@ int SCSIBR::ReadFsResult(BYTE *buf) const
|
||||
// Read Filesystem (return data)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIBR::ReadFsOut(BYTE *buf) const
|
||||
int SCSIBR::ReadFsOut(vector<BYTE>& buf) const
|
||||
{
|
||||
memcpy(buf, fsout, fsoutlen);
|
||||
copy_n(fsout.begin(), fsoutlen, buf.begin());
|
||||
return fsoutlen;
|
||||
}
|
||||
|
||||
@ -1077,9 +1045,9 @@ int SCSIBR::ReadFsOut(BYTE *buf) const
|
||||
// Read file system (return option data)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIBR::ReadFsOpt(BYTE *buf) const
|
||||
int SCSIBR::ReadFsOpt(vector<BYTE>& buf) const
|
||||
{
|
||||
memcpy(buf, fsopt, fsoptlen);
|
||||
copy_n(fsopt.begin(), fsoptlen, buf.begin());
|
||||
return fsoptlen;
|
||||
}
|
||||
|
||||
@ -1088,7 +1056,7 @@ int SCSIBR::ReadFsOpt(BYTE *buf) const
|
||||
// Write Filesystem
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::WriteFs(int func, BYTE *buf)
|
||||
void SCSIBR::WriteFs(int func, vector<BYTE>& buf)
|
||||
{
|
||||
fsresult = FS_FATAL_INVALIDCOMMAND;
|
||||
fsoutlen = 0;
|
||||
@ -1096,32 +1064,83 @@ void SCSIBR::WriteFs(int func, BYTE *buf)
|
||||
|
||||
func &= 0x1f;
|
||||
switch (func) {
|
||||
case 0x00: return FS_InitDevice(buf); // $40 - start device
|
||||
case 0x01: return FS_CheckDir(buf); // $41 - directory check
|
||||
case 0x02: return FS_MakeDir(buf); // $42 - create directory
|
||||
case 0x03: return FS_RemoveDir(buf); // $43 - remove directory
|
||||
case 0x04: return FS_Rename(buf); // $44 - change file name
|
||||
case 0x05: return FS_Delete(buf); // $45 - delete file
|
||||
case 0x06: return FS_Attribute(buf); // $46 - Get/set file attribute
|
||||
case 0x07: return FS_Files(buf); // $47 - file search
|
||||
case 0x08: return FS_NFiles(buf); // $48 - next file search
|
||||
case 0x09: return FS_Create(buf); // $49 - create file
|
||||
case 0x0A: return FS_Open(buf); // $4A - File open
|
||||
case 0x0B: return FS_Close(buf); // $4B - File close
|
||||
case 0x0C: return FS_Read(buf); // $4C - read file
|
||||
case 0x0D: return FS_Write(buf); // $4D - write file
|
||||
case 0x0E: return FS_Seek(buf); // $4E - File seek
|
||||
case 0x0F: return FS_TimeStamp(buf); // $4F - Get/set file modification time
|
||||
case 0x10: return FS_GetCapacity(buf); // $50 - get capacity
|
||||
case 0x11: return FS_CtrlDrive(buf); // $51 - Drive control/state check
|
||||
case 0x12: return FS_GetDPB(buf); // $52 - Get DPB
|
||||
case 0x13: return FS_DiskRead(buf); // $53 - read sector
|
||||
case 0x14: return FS_DiskWrite(buf); // $54 - write sector
|
||||
case 0x15: return FS_Ioctrl(buf); // $55 - IOCTRL
|
||||
case 0x16: return FS_Flush(buf); // $56 - flush
|
||||
case 0x17: return FS_CheckMedia(buf); // $57 - check media exchange
|
||||
case 0x18: return FS_Lock(buf); // $58 - exclusive control
|
||||
default: break;
|
||||
case 0x00:
|
||||
FS_InitDevice(buf); // $40 - start device
|
||||
break;
|
||||
case 0x01:
|
||||
FS_CheckDir(buf); // $41 - directory check
|
||||
break;
|
||||
case 0x02:
|
||||
FS_MakeDir(buf); // $42 - create directory
|
||||
break;
|
||||
case 0x03:
|
||||
FS_RemoveDir(buf); // $43 - remove directory
|
||||
break;
|
||||
case 0x04:
|
||||
FS_Rename(buf); // $44 - change file name
|
||||
break;
|
||||
case 0x05:
|
||||
FS_Delete(buf); // $45 - delete file
|
||||
break;
|
||||
case 0x06:
|
||||
FS_Attribute(buf); // $46 - Get/set file attribute
|
||||
break;
|
||||
case 0x07:
|
||||
FS_Files(buf); // $47 - file search
|
||||
break;
|
||||
case 0x08:
|
||||
FS_NFiles(buf); // $48 - next file search
|
||||
break;
|
||||
case 0x09:
|
||||
FS_Create(buf); // $49 - create file
|
||||
break;
|
||||
case 0x0A:
|
||||
FS_Open(buf); // $4A - File open
|
||||
break;
|
||||
case 0x0B:
|
||||
FS_Close(buf); // $4B - File close
|
||||
break;
|
||||
case 0x0C:
|
||||
FS_Read(buf); // $4C - read file
|
||||
break;
|
||||
case 0x0D:
|
||||
FS_Write(buf); // $4D - write file
|
||||
break;
|
||||
case 0x0E:
|
||||
FS_Seek(buf); // $4E - File seek
|
||||
break;
|
||||
case 0x0F:
|
||||
FS_TimeStamp(buf); // $4F - Get/set file modification time
|
||||
break;
|
||||
case 0x10:
|
||||
FS_GetCapacity(buf); // $50 - get capacity
|
||||
break;
|
||||
case 0x11:
|
||||
FS_CtrlDrive(buf); // $51 - Drive control/state check
|
||||
break;
|
||||
case 0x12:
|
||||
FS_GetDPB(buf); // $52 - Get DPB
|
||||
break;
|
||||
case 0x13:
|
||||
FS_DiskRead(buf); // $53 - read sector
|
||||
break;
|
||||
case 0x14:
|
||||
FS_DiskWrite(buf); // $54 - write sector
|
||||
break;
|
||||
case 0x15:
|
||||
FS_Ioctrl(buf); // $55 - IOCTRL
|
||||
break;
|
||||
case 0x16:
|
||||
FS_Flush(buf); // $56 - flush
|
||||
break;
|
||||
case 0x17:
|
||||
FS_CheckMedia(buf); // $57 - check media exchange
|
||||
break;
|
||||
case 0x18:
|
||||
FS_Lock(buf); // $58 - exclusive control
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1130,7 +1149,7 @@ void SCSIBR::WriteFs(int func, BYTE *buf)
|
||||
// File system write (input option data)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIBR::WriteFsOpt(const BYTE *buf, int num)
|
||||
void SCSIBR::WriteFsOpt(const vector<BYTE>& buf, int num)
|
||||
{
|
||||
memcpy(fsopt, buf, num);
|
||||
copy_n(buf.begin(), num, fsopt.begin());
|
||||
}
|
||||
|
@ -22,13 +22,18 @@
|
||||
#include "ctapdriver.h"
|
||||
#include "cfilesystem.h"
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
class SCSIBR final : public Disk
|
||||
{
|
||||
static constexpr const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
public:
|
||||
|
||||
SCSIBR();
|
||||
~SCSIBR() override;
|
||||
~SCSIBR() override = default;
|
||||
SCSIBR(SCSIBR&) = delete;
|
||||
SCSIBR& operator=(const SCSIBR&) = delete;
|
||||
|
||||
@ -37,8 +42,8 @@ public:
|
||||
|
||||
// Commands
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int GetMessage10(const vector<int>&, BYTE *);
|
||||
bool WriteBytes(const vector<int>&, BYTE *, uint64_t);
|
||||
int GetMessage10(const vector<int>&, vector<BYTE>&);
|
||||
bool WriteBytes(const vector<int>&, vector<BYTE>&, uint64_t);
|
||||
void TestUnitReady() override;
|
||||
void GetMessage10();
|
||||
void SendMessage10();
|
||||
@ -49,56 +54,56 @@ private:
|
||||
|
||||
Dispatcher<SCSIBR> dispatcher;
|
||||
|
||||
int GetMacAddr(BYTE *buf) const; // Get MAC address
|
||||
void SetMacAddr(const BYTE *buf); // Set MAC address
|
||||
int GetMacAddr(vector<BYTE>&) const; // Get MAC address
|
||||
void SetMacAddr(const vector<BYTE>&); // Set MAC address
|
||||
void ReceivePacket(); // Receive a packet
|
||||
void GetPacketBuf(BYTE *buf); // Get a packet
|
||||
void SendPacket(const BYTE *buf, int len); // Send a packet
|
||||
void GetPacketBuf(vector<BYTE>&, int); // Get a packet
|
||||
void SendPacket(const vector<BYTE>&, int); // Send a packet
|
||||
|
||||
CTapDriver tap; // TAP driver
|
||||
bool m_bTapEnable = false; // TAP valid flag
|
||||
BYTE mac_addr[6]; // MAC Addres
|
||||
array<BYTE, 6> mac_addr = {}; // MAC Address
|
||||
int packet_len = 0; // Receive packet size
|
||||
BYTE packet_buf[0x1000]; // Receive packet buffer
|
||||
array<BYTE, 0x1000> packet_buf; // Receive packet buffer
|
||||
bool packet_enable = false; // Received packet valid
|
||||
|
||||
int ReadFsResult(BYTE *buf) const; // Read filesystem (result code)
|
||||
int ReadFsOut(BYTE *buf) const; // Read filesystem (return data)
|
||||
int ReadFsOpt(BYTE *buf) const; // Read file system (optional data)
|
||||
void WriteFs(int func, BYTE *buf); // File system write (execute)
|
||||
void WriteFsOpt(const BYTE *buf, int len); // File system write (optional data)
|
||||
int ReadFsResult(vector<BYTE>&) const; // Read filesystem (result code)
|
||||
int ReadFsOut(vector<BYTE>&) const; // Read filesystem (return data)
|
||||
int ReadFsOpt(vector<BYTE>&) const; // Read file system (optional data)
|
||||
void WriteFs(int, vector<BYTE>&); // File system write (execute)
|
||||
void WriteFsOpt(const vector<BYTE>&, int); // File system write (optional data)
|
||||
|
||||
// Command handlers
|
||||
void FS_InitDevice(BYTE *buf); // $40 - boot
|
||||
void FS_CheckDir(BYTE *buf); // $41 - directory check
|
||||
void FS_MakeDir(BYTE *buf); // $42 - create directory
|
||||
void FS_RemoveDir(BYTE *buf); // $43 - delete directory
|
||||
void FS_Rename(BYTE *buf); // $44 - change filename
|
||||
void FS_Delete(BYTE *buf); // $45 - delete file
|
||||
void FS_Attribute(BYTE *buf); // $46 - get/set file attributes
|
||||
void FS_Files(BYTE *buf); // $47 - file search
|
||||
void FS_NFiles(BYTE *buf); // $48 - find next file
|
||||
void FS_Create(BYTE *buf); // $49 - create file
|
||||
void FS_Open(BYTE *buf); // $4A - open file
|
||||
void FS_Close(BYTE *buf); // $4B - close file
|
||||
void FS_Read(BYTE *buf); // $4C - read file
|
||||
void FS_Write(BYTE *buf); // $4D - write file
|
||||
void FS_Seek(BYTE *buf); // $4E - seek file
|
||||
void FS_TimeStamp(BYTE *buf); // $4F - get/set file time
|
||||
void FS_GetCapacity(BYTE *buf); // $50 - get capacity
|
||||
void FS_CtrlDrive(BYTE *buf); // $51 - drive status check/control
|
||||
void FS_GetDPB(BYTE *buf); // $52 - get DPB
|
||||
void FS_DiskRead(BYTE *buf); // $53 - read sector
|
||||
void FS_DiskWrite(BYTE *buf); // $54 - write sector
|
||||
void FS_Ioctrl(BYTE *buf); // $55 - IOCTRL
|
||||
void FS_Flush(BYTE *buf); // $56 - flush cache
|
||||
void FS_CheckMedia(BYTE *buf); // $57 - check media
|
||||
void FS_Lock(BYTE *buf); // $58 - get exclusive control
|
||||
void FS_InitDevice(vector<BYTE>&); // $40 - boot
|
||||
void FS_CheckDir(vector<BYTE>&); // $41 - directory check
|
||||
void FS_MakeDir(vector<BYTE>&); // $42 - create directory
|
||||
void FS_RemoveDir(vector<BYTE>&); // $43 - delete directory
|
||||
void FS_Rename(vector<BYTE>&); // $44 - change filename
|
||||
void FS_Delete(vector<BYTE>&); // $45 - delete file
|
||||
void FS_Attribute(vector<BYTE>&); // $46 - get/set file attributes
|
||||
void FS_Files(vector<BYTE>&); // $47 - file search
|
||||
void FS_NFiles(vector<BYTE>&); // $48 - find next file
|
||||
void FS_Create(vector<BYTE>&); // $49 - create file
|
||||
void FS_Open(vector<BYTE>&); // $4A - open file
|
||||
void FS_Close(vector<BYTE>&); // $4B - close file
|
||||
void FS_Read(vector<BYTE>&); // $4C - read file
|
||||
void FS_Write(vector<BYTE>&); // $4D - write file
|
||||
void FS_Seek(vector<BYTE>&); // $4E - seek file
|
||||
void FS_TimeStamp(vector<BYTE>&); // $4F - get/set file time
|
||||
void FS_GetCapacity(vector<BYTE>&); // $50 - get capacity
|
||||
void FS_CtrlDrive(vector<BYTE>&); // $51 - drive status check/control
|
||||
void FS_GetDPB(vector<BYTE>&); // $52 - get DPB
|
||||
void FS_DiskRead(vector<BYTE>&); // $53 - read sector
|
||||
void FS_DiskWrite(vector<BYTE>&); // $54 - write sector
|
||||
void FS_Ioctrl(vector<BYTE>&); // $55 - IOCTRL
|
||||
void FS_Flush(vector<BYTE>&); // $56 - flush cache
|
||||
void FS_CheckMedia(vector<BYTE>&); // $57 - check media
|
||||
void FS_Lock(vector<BYTE>&); // $58 - get exclusive control
|
||||
|
||||
CFileSys fs; // File system accessor
|
||||
DWORD fsresult = 0; // File system access result code
|
||||
BYTE fsout[0x800]; // File system access result buffer
|
||||
array<BYTE, 0x800> fsout; // File system access result buffer
|
||||
DWORD fsoutlen = 0; // File system access result buffer size
|
||||
BYTE fsopt[0x1000000]; // File system access buffer
|
||||
array<BYTE, 0x1000000> fsopt; // File system access buffer
|
||||
DWORD fsoptlen = 0; // File system access buffer size
|
||||
};
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "../rasutil.h"
|
||||
#include "dispatcher.h"
|
||||
#include "scsi_printer.h"
|
||||
@ -48,6 +49,7 @@
|
||||
using namespace std;
|
||||
using namespace scsi_defs;
|
||||
using namespace ras_util;
|
||||
using namespace scsi_command_util;
|
||||
|
||||
SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP")
|
||||
{
|
||||
@ -143,18 +145,13 @@ void SCSIPrinter::Print()
|
||||
{
|
||||
CheckReservation();
|
||||
|
||||
uint32_t length = ctrl->cmd[2];
|
||||
length <<= 8;
|
||||
length |= ctrl->cmd[3];
|
||||
length <<= 8;
|
||||
length |= ctrl->cmd[4];
|
||||
uint32_t length = GetInt24(ctrl->cmd, 2);
|
||||
|
||||
LOGTRACE("Receiving %d byte(s) to be printed", length)
|
||||
|
||||
// TODO This device suffers from the statically allocated buffer size,
|
||||
// see https://github.com/akuker/RASCSI/issues/669
|
||||
if (length > (uint32_t)ctrl->bufsize) {
|
||||
LOGERROR("Transfer buffer overflow")
|
||||
if (length > controller->GetBufferSize()) {
|
||||
LOGERROR("%s", string("Transfer buffer overflow: Buffer size is " + to_string(controller->GetBufferSize()) +
|
||||
" bytes, " + to_string(length) + " bytes expected").c_str())
|
||||
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
@ -217,7 +214,7 @@ void SCSIPrinter::StopPrint()
|
||||
TestUnitReady();
|
||||
}
|
||||
|
||||
bool SCSIPrinter::WriteByteSequence(BYTE *buf, uint32_t length)
|
||||
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
|
||||
{
|
||||
if (fd == -1) {
|
||||
strcpy(filename, TMP_FILE_PATTERN);
|
||||
@ -232,7 +229,7 @@ bool SCSIPrinter::WriteByteSequence(BYTE *buf, uint32_t length)
|
||||
|
||||
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename)
|
||||
|
||||
auto num_written = (uint32_t)write(fd, buf, length);
|
||||
auto num_written = (uint32_t)write(fd, buf.data(), length);
|
||||
|
||||
return num_written == length;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
void SendDiagnostic() override;
|
||||
void StopPrint();
|
||||
|
||||
bool WriteByteSequence(BYTE *, uint32_t) override;
|
||||
bool WriteByteSequence(vector<BYTE>&, uint32_t) override;
|
||||
void CheckReservation();
|
||||
void DiscardReservation();
|
||||
void Cleanup();
|
||||
|
@ -32,11 +32,6 @@ SCSICD::SCSICD(const unordered_set<uint32_t>& sector_sizes) : Disk("SCCD")
|
||||
dispatcher.Add(scsi_command::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
|
||||
}
|
||||
|
||||
SCSICD::~SCSICD()
|
||||
{
|
||||
ClearTrack();
|
||||
}
|
||||
|
||||
bool SCSICD::Dispatch(scsi_command cmd)
|
||||
{
|
||||
// The superclass class handles the less specific commands
|
||||
@ -97,8 +92,10 @@ void SCSICD::Open(const Filepath& path)
|
||||
super::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
|
||||
SetUpCache(path);
|
||||
|
||||
// Set RAW flag
|
||||
disk.dcache->SetRawMode(rawfile);
|
||||
cache->SetRawMode(rawfile);
|
||||
|
||||
// Attention if ready
|
||||
if (IsReady()) {
|
||||
@ -120,8 +117,8 @@ void SCSICD::OpenIso(const Filepath& path)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
off_t size = fio.GetFileSize();
|
||||
if (size < 0x800) {
|
||||
off_t file_size = fio.GetFileSize();
|
||||
if (file_size < 0x800) {
|
||||
fio.Close();
|
||||
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
|
||||
}
|
||||
@ -135,7 +132,7 @@ void SCSICD::OpenIso(const Filepath& path)
|
||||
|
||||
// Check if it is RAW format
|
||||
array<BYTE, 12> sync;
|
||||
memset(sync.data(), 0xff, sync.size());
|
||||
sync.fill(0xff);
|
||||
sync[0] = 0x00;
|
||||
sync[11] = 0x00;
|
||||
rawfile = false;
|
||||
@ -160,16 +157,16 @@ void SCSICD::OpenIso(const Filepath& path)
|
||||
|
||||
if (rawfile) {
|
||||
// Size must be a multiple of 2536
|
||||
if (size % 2536) {
|
||||
if (file_size % 2536) {
|
||||
throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes but is "
|
||||
+ to_string(size) + " bytes");
|
||||
+ to_string(file_size) + " bytes");
|
||||
}
|
||||
|
||||
// Set the number of blocks
|
||||
SetBlockCount((DWORD)(size / 0x930));
|
||||
SetBlockCount((DWORD)(file_size / 0x930));
|
||||
} else {
|
||||
// Set the number of blocks
|
||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||
SetBlockCount((DWORD)(file_size >> GetSectorSizeShiftCount()));
|
||||
}
|
||||
|
||||
// Create only one data track
|
||||
@ -216,7 +213,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
|
||||
|
||||
void SCSICD::ReadToc()
|
||||
{
|
||||
ctrl->length = ReadTocInternal(ctrl->cmd, ctrl->buffer);
|
||||
ctrl->length = ReadTocInternal(ctrl->cmd, controller->GetBuffer());
|
||||
|
||||
EnterDataInPhase();
|
||||
}
|
||||
@ -276,11 +273,8 @@ void SCSICD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changea
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
|
||||
int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
|
||||
{
|
||||
assert(buf);
|
||||
|
||||
CheckReady();
|
||||
|
||||
// Search for the track
|
||||
@ -295,10 +289,6 @@ int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
|
||||
|
||||
// If different from the current data track
|
||||
if (dataindex != index) {
|
||||
// Delete current disk cache (no need to save)
|
||||
delete disk.dcache;
|
||||
disk.dcache = nullptr;
|
||||
|
||||
// Reset the number of blocks
|
||||
SetBlockCount(tracks[index]->GetBlocks());
|
||||
assert(GetBlockCount() > 0);
|
||||
@ -306,8 +296,9 @@ int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
|
||||
// Recreate the disk cache
|
||||
Filepath path;
|
||||
tracks[index]->GetPath(path);
|
||||
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount());
|
||||
disk.dcache->SetRawMode(rawfile);
|
||||
// Re-assign disk cache (no need to save)
|
||||
cache.reset(new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount()));
|
||||
cache->SetRawMode(rawfile);
|
||||
|
||||
// Reset data index
|
||||
dataindex = index;
|
||||
@ -318,7 +309,7 @@ int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
|
||||
return super::Read(cdb, buf, block);
|
||||
}
|
||||
|
||||
int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
|
||||
int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
@ -327,9 +318,8 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
|
||||
assert(tracks[0]);
|
||||
|
||||
// Get allocation length, clear buffer
|
||||
int length = cdb[7] << 8;
|
||||
length |= cdb[8];
|
||||
memset(buf, 0, length);
|
||||
int length = GetInt16(cdb, 7);
|
||||
fill_n(buf.data(), length, 0);
|
||||
|
||||
// Get MSF Flag
|
||||
bool msf = cdb[1] & 0x02;
|
||||
@ -365,7 +355,7 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
|
||||
if (msf) {
|
||||
LBAtoMSF(lba, &buf[8]);
|
||||
} else {
|
||||
SetInt16(&buf[10], lba);
|
||||
SetInt16(buf, 10, lba);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@ -380,34 +370,35 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
|
||||
assert(loop >= 1);
|
||||
|
||||
// Create header
|
||||
SetInt16(&buf[0], (loop << 3) + 2);
|
||||
SetInt16(buf, 0, (loop << 3) + 2);
|
||||
buf[2] = (BYTE)tracks[0]->GetTrackNo();
|
||||
buf[3] = (BYTE)last;
|
||||
buf += 4;
|
||||
|
||||
int offset = 4;
|
||||
|
||||
// Loop....
|
||||
for (int i = 0; i < loop; i++) {
|
||||
// ADR and Control
|
||||
if (tracks[index]->IsAudio()) {
|
||||
// audio track
|
||||
buf[1] = 0x10;
|
||||
buf[offset + 1] = 0x10;
|
||||
} else {
|
||||
// data track
|
||||
buf[1] = 0x14;
|
||||
buf[offset + 1] = 0x14;
|
||||
}
|
||||
|
||||
// track number
|
||||
buf[2] = (BYTE)tracks[index]->GetTrackNo();
|
||||
buf[offset + 2] = (BYTE)tracks[index]->GetTrackNo();
|
||||
|
||||
// track address
|
||||
if (msf) {
|
||||
LBAtoMSF(tracks[index]->GetFirst(), &buf[4]);
|
||||
LBAtoMSF(tracks[index]->GetFirst(), &buf[offset + 4]);
|
||||
} else {
|
||||
SetInt16(&buf[6], tracks[index]->GetFirst());
|
||||
SetInt16(buf, offset + 6, tracks[index]->GetFirst());
|
||||
}
|
||||
|
||||
// Advance buffer pointer and index
|
||||
buf += 8;
|
||||
offset += 8;
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ class SCSICD : public Disk, public ScsiMmcCommands, public FileSupport
|
||||
public:
|
||||
|
||||
explicit SCSICD(const unordered_set<uint32_t>&);
|
||||
~SCSICD() override;
|
||||
~SCSICD() override = default;
|
||||
SCSICD(SCSICD&) = delete;
|
||||
SCSICD& operator=(const SCSICD&) = delete;
|
||||
|
||||
@ -38,7 +38,7 @@ public:
|
||||
|
||||
// Commands
|
||||
vector<byte> InquiryInternal() const override;
|
||||
int Read(const vector<int>&, BYTE *, uint64_t) override;
|
||||
int Read(const vector<int>&, vector<BYTE>&, uint64_t) override;
|
||||
|
||||
protected:
|
||||
|
||||
@ -51,7 +51,7 @@ private:
|
||||
|
||||
Dispatcher<SCSICD> dispatcher;
|
||||
|
||||
int ReadTocInternal(const vector<int>&, BYTE *);
|
||||
int ReadTocInternal(const vector<int>&, vector<BYTE>&);
|
||||
|
||||
void AddCDROMPage(map<int, vector<byte>>&, bool) const;
|
||||
void AddCDDAPage(map<int, vector<byte>>&, bool) const;
|
||||
|
@ -30,7 +30,7 @@ SCSIHD::SCSIHD(const unordered_set<uint32_t>& sector_sizes, bool removable, scsi
|
||||
SetSectorSizes(sector_sizes);
|
||||
}
|
||||
|
||||
void SCSIHD::FinalizeSetup(const Filepath &path, off_t size)
|
||||
void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
|
||||
{
|
||||
// 2TB is the current maximum
|
||||
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
||||
@ -60,6 +60,8 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size)
|
||||
|
||||
Disk::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
|
||||
SetUpCache(path, image_offset);
|
||||
}
|
||||
|
||||
void SCSIHD::Open(const Filepath& path)
|
||||
@ -73,17 +75,17 @@ void SCSIHD::Open(const Filepath& path)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
off_t size = fio.GetFileSize();
|
||||
off_t file_size = fio.GetFileSize();
|
||||
fio.Close();
|
||||
|
||||
// Sector size (default 512 bytes) and number of blocks
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
|
||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||
SetBlockCount((DWORD)(file_size >> GetSectorSizeShiftCount()));
|
||||
|
||||
// Effective size must be a multiple of the sector size
|
||||
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
|
||||
file_size = (file_size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
|
||||
|
||||
FinalizeSetup(path, size);
|
||||
FinalizeSetup(path, file_size);
|
||||
}
|
||||
|
||||
vector<byte> SCSIHD::InquiryInternal() const
|
||||
@ -91,7 +93,7 @@ vector<byte> SCSIHD::InquiryInternal() const
|
||||
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level, IsRemovable());
|
||||
}
|
||||
|
||||
void SCSIHD::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length) const
|
||||
void SCSIHD::ModeSelect(const vector<int>& cdb, const vector<BYTE>& buf, int length) const
|
||||
{
|
||||
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ public:
|
||||
SCSIHD(SCSIHD&) = delete;
|
||||
SCSIHD& operator=(const SCSIHD&) = delete;
|
||||
|
||||
void FinalizeSetup(const Filepath&, off_t);
|
||||
void FinalizeSetup(const Filepath&, off_t, off_t = 0);
|
||||
|
||||
void Open(const Filepath&) override;
|
||||
|
||||
// Commands
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void ModeSelect(const vector<int>&, const BYTE *, int) const override;
|
||||
void ModeSelect(const vector<int>&, const vector<BYTE>&, int) const override;
|
||||
|
||||
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
|
||||
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
|
||||
|
@ -30,7 +30,7 @@ const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
|
||||
//---------------------------------------------------------------------------
|
||||
static inline int getWordLE(const BYTE *b)
|
||||
{
|
||||
return (b[1] << 8) | b[0];
|
||||
return ((int)b[1] << 8) | (int)b[0];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -38,9 +38,9 @@ static inline int getWordLE(const BYTE *b)
|
||||
// Extract longwords assumed to be little endian
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static inline DWORD getDwordLE(const BYTE *b)
|
||||
static inline uint32_t getDwordLE(const BYTE *b)
|
||||
{
|
||||
return ((DWORD)(b[3]) << 24) | ((DWORD)(b[2]) << 16) | ((DWORD)(b[1]) << 8) | b[0];
|
||||
return ((uint32_t)(b[3]) << 24) | ((uint32_t)(b[2]) << 16) | ((uint32_t)(b[1]) << 8) | b[0];
|
||||
}
|
||||
|
||||
void SCSIHD_NEC::Open(const Filepath& path)
|
||||
@ -54,18 +54,18 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
off_t size = fio.GetFileSize();
|
||||
off_t file_size = fio.GetFileSize();
|
||||
|
||||
// NEC root sector
|
||||
array<BYTE, 512> root_sector;
|
||||
if (size >= (off_t)root_sector.size() && !fio.Read(root_sector.data(), root_sector.size())) {
|
||||
if (file_size >= (off_t)root_sector.size() && !fio.Read(root_sector.data(), root_sector.size())) {
|
||||
fio.Close();
|
||||
throw io_exception("Can't read NEC hard disk file root sector");
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
// Effective size must be a multiple of 512
|
||||
size = (size / 512) * 512;
|
||||
file_size = (file_size / 512) * 512;
|
||||
|
||||
int image_size = 0;
|
||||
int sector_size = 0;
|
||||
@ -75,18 +75,18 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
||||
// PC-9801-55 NEC genuine?
|
||||
if (const char *ext = path.GetFileExt(); !strcasecmp(ext, ".hdn")) {
|
||||
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
|
||||
disk.image_offset = 0;
|
||||
image_size = (int)size;
|
||||
image_offset = 0;
|
||||
image_size = (int)file_size;
|
||||
sector_size = 512;
|
||||
sectors = 25;
|
||||
heads = 8;
|
||||
cylinders = (int)(size >> 9);
|
||||
cylinders = (int)(file_size >> 9);
|
||||
cylinders >>= 3;
|
||||
cylinders /= 25;
|
||||
}
|
||||
// Anex86 HD image?
|
||||
else if (!strcasecmp(ext, ".hdi")) {
|
||||
disk.image_offset = getDwordLE(&root_sector[8]);
|
||||
image_offset = getDwordLE(&root_sector[8]);
|
||||
image_size = getDwordLE(&root_sector[12]);
|
||||
sector_size = getDwordLE(&root_sector[16]);
|
||||
sectors = getDwordLE(&root_sector[20]);
|
||||
@ -96,7 +96,7 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
||||
// T98Next HD image?
|
||||
else if (!strcasecmp(ext, ".nhd")) {
|
||||
if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) {
|
||||
disk.image_offset = getDwordLE(&root_sector[0x110]);
|
||||
image_offset = getDwordLE(&root_sector[0x110]);
|
||||
cylinders = getDwordLE(&root_sector[0x114]);
|
||||
heads = getWordLE(&root_sector[0x118]);
|
||||
sectors = getWordLE(&root_sector[0x11a]);
|
||||
@ -113,24 +113,23 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
||||
}
|
||||
|
||||
// Image size consistency check
|
||||
if (disk.image_offset + image_size > size || image_size % sector_size != 0) {
|
||||
if (image_offset + image_size > file_size || image_size % sector_size != 0) {
|
||||
throw io_exception("Image size consistency check failed");
|
||||
}
|
||||
|
||||
// Calculate sector size
|
||||
for (size = 16; size > 0; --size) {
|
||||
if ((1 << size) == sector_size)
|
||||
for (file_size = 16; file_size > 0; --file_size) {
|
||||
if ((1 << file_size) == sector_size)
|
||||
break;
|
||||
}
|
||||
if (size <= 0 || size > 16) {
|
||||
if (file_size <= 0 || file_size > 16) {
|
||||
throw io_exception("Invalid NEC disk size");
|
||||
}
|
||||
SetSectorSizeShiftCount((uint32_t)size);
|
||||
SetSectorSizeShiftCount((uint32_t)file_size);
|
||||
|
||||
// Number of blocks
|
||||
SetBlockCount(image_size >> disk.size);
|
||||
SetBlockCount(image_size >> GetSectorSizeShiftCount());
|
||||
|
||||
FinalizeSetup(path, size);
|
||||
FinalizeSetup(path, file_size, image_offset);
|
||||
}
|
||||
|
||||
vector<byte> SCSIHD_NEC::InquiryInternal() const
|
||||
@ -171,7 +170,7 @@ void SCSIHD_NEC::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) c
|
||||
SetInt16(buf, 0x0a, sectors);
|
||||
|
||||
// Set the number of bytes in the physical sector
|
||||
SetInt16(buf, 0x0c, 1 << disk.size);
|
||||
SetInt16(buf, 0x0c, GetSectorSizeInBytes());
|
||||
}
|
||||
|
||||
// Set removable attributes (remains of the old days)
|
||||
|
@ -13,9 +13,14 @@
|
||||
// [ SCSI NEC "Genuine" Hard Disk]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scsihd.h"
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
@ -24,16 +29,14 @@
|
||||
//===========================================================================
|
||||
class SCSIHD_NEC : public SCSIHD
|
||||
{
|
||||
static const unordered_set<uint32_t> sector_sizes;
|
||||
|
||||
public:
|
||||
|
||||
explicit SCSIHD_NEC() : SCSIHD(sector_sizes, false) {}
|
||||
SCSIHD_NEC() : SCSIHD(sector_sizes, false) {}
|
||||
~SCSIHD_NEC() override = default;
|
||||
SCSIHD_NEC(SCSIHD_NEC&) = delete;
|
||||
SCSIHD_NEC& operator=(const SCSIHD_NEC&) = delete;
|
||||
|
||||
void Open(const Filepath& path) override;
|
||||
void Open(const Filepath&) override;
|
||||
|
||||
vector<byte> InquiryInternal() const override;
|
||||
|
||||
@ -43,6 +46,11 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static const unordered_set<uint32_t> sector_sizes;
|
||||
|
||||
// Image file offset (NEC only)
|
||||
off_t image_offset = 0;
|
||||
|
||||
// Geometry data
|
||||
int cylinders = 0;
|
||||
int heads = 0;
|
||||
|
@ -7,11 +7,9 @@
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI Magneto-Optical Disk]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "fileio.h"
|
||||
@ -21,11 +19,18 @@
|
||||
|
||||
using namespace scsi_command_util;
|
||||
|
||||
SCSIMO::SCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries)
|
||||
: Disk("SCMO")
|
||||
SCSIMO::SCSIMO(const unordered_set<uint32_t>& sector_sizes) : Disk("SCMO")
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
SetGeometries(geometries);
|
||||
|
||||
// 128 MB, 512 bytes per sector, 248826 sectors
|
||||
geometries[512 * 248826] = make_pair(512, 248826);
|
||||
// 230 MB, 512 bytes per block, 446325 sectors
|
||||
geometries[512 * 446325] = make_pair(512, 446325);
|
||||
// 540 MB, 512 bytes per sector, 1041500 sectors
|
||||
geometries[512 * 1041500] = make_pair(512, 1041500);
|
||||
// 640 MB, 20248 bytes per sector, 310352 sectors
|
||||
geometries[2048 * 310352] = make_pair(2048, 310352);
|
||||
}
|
||||
|
||||
void SCSIMO::Open(const Filepath& path)
|
||||
@ -40,15 +45,14 @@ void SCSIMO::Open(const Filepath& path)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
off_t size = fio.GetFileSize();
|
||||
off_t file_size = fio.GetFileSize();
|
||||
fio.Close();
|
||||
|
||||
// For some priorities there are hard-coded, well-defined sector sizes and block counts
|
||||
// TODO Find a more flexible solution
|
||||
if (!SetGeometryForCapacity(size)) {
|
||||
// For some capacities there are hard-coded, well-defined sector sizes and block counts
|
||||
if (!SetGeometryForCapacity(file_size)) {
|
||||
// Sector size (default 512 bytes) and number of blocks
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
|
||||
SetBlockCount(size >> GetSectorSizeShiftCount());
|
||||
SetBlockCount(file_size >> GetSectorSizeShiftCount());
|
||||
}
|
||||
|
||||
SetReadOnly(false);
|
||||
@ -58,6 +62,8 @@ void SCSIMO::Open(const Filepath& path)
|
||||
Disk::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
|
||||
SetUpCache(path);
|
||||
|
||||
// Attention if ready
|
||||
if (IsReady()) {
|
||||
SetAttn(true);
|
||||
@ -94,7 +100,7 @@ void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
|
||||
// Do not report update blocks
|
||||
}
|
||||
|
||||
void SCSIMO::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length) const
|
||||
void SCSIMO::ModeSelect(const vector<int>& cdb, const vector<BYTE>& buf, int length) const
|
||||
{
|
||||
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
|
||||
}
|
||||
|
@ -5,12 +5,10 @@
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI Magneto-Optical Disk]
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -20,11 +18,13 @@
|
||||
#include "file_support.h"
|
||||
#include "filepath.h"
|
||||
|
||||
using Geometry = pair<uint32_t, uint32_t>;
|
||||
|
||||
class SCSIMO : public Disk, public FileSupport
|
||||
{
|
||||
public:
|
||||
|
||||
SCSIMO(const unordered_set<uint32_t>&, const unordered_map<uint64_t, Geometry>&);
|
||||
explicit SCSIMO(const unordered_set<uint32_t>&);
|
||||
~SCSIMO() override = default;
|
||||
SCSIMO(SCSIMO&) = delete;
|
||||
SCSIMO& operator=(const SCSIMO&) = delete;
|
||||
@ -32,7 +32,7 @@ public:
|
||||
void Open(const Filepath&) override;
|
||||
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void ModeSelect(const vector<int>&, const BYTE *, int) const override;
|
||||
void ModeSelect(const vector<int>&, const vector<BYTE>&, int) const override;
|
||||
|
||||
protected:
|
||||
|
||||
@ -44,7 +44,6 @@ private:
|
||||
|
||||
void AddOptionPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
void SetGeometries(const unordered_map<uint64_t, Geometry>& g) { geometries = g; }
|
||||
bool SetGeometryForCapacity(uint64_t);
|
||||
|
||||
// The mapping of supported capacities to block sizes and block counts, empty if there is no capacity restriction
|
||||
|
@ -42,10 +42,6 @@ bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
|
||||
break;
|
||||
|
||||
case OpenMode::ReadWrite:
|
||||
// Make sure RW does not succeed when reading from CD-ROM
|
||||
if (access(fname, 0x06) != 0) {
|
||||
return false;
|
||||
}
|
||||
handle = open(fname, O_RDWR | omode);
|
||||
break;
|
||||
|
||||
@ -115,7 +111,7 @@ off_t Fileio::GetFileSize() const
|
||||
assert(handle >= 0);
|
||||
|
||||
// Get file position in 64bit
|
||||
off_t cur = GetFilePos();
|
||||
off_t cur = lseek(handle, 0, SEEK_CUR);
|
||||
|
||||
// Get file size in64bitで
|
||||
off_t end = lseek(handle, 0, SEEK_END);
|
||||
@ -126,14 +122,6 @@ off_t Fileio::GetFileSize() const
|
||||
return end;
|
||||
}
|
||||
|
||||
off_t Fileio::GetFilePos() const
|
||||
{
|
||||
assert(handle >= 0);
|
||||
|
||||
// Get file position in 64bit
|
||||
return lseek(handle, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
void Fileio::Close()
|
||||
{
|
||||
if (handle != -1) {
|
||||
|
@ -35,7 +35,6 @@ public:
|
||||
bool Read(BYTE *buffer, int size) const;
|
||||
bool Write(const BYTE *buffer, int size) const;
|
||||
off_t GetFileSize() const;
|
||||
off_t GetFilePos() const;
|
||||
void Close();
|
||||
|
||||
private:
|
||||
|
@ -31,44 +31,40 @@ using namespace std;
|
||||
// imported from bcm_host.c
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static DWORD get_dt_ranges(const char *filename, DWORD offset)
|
||||
static uint32_t get_dt_ranges(const char *filename, DWORD offset)
|
||||
{
|
||||
DWORD address = ~0;
|
||||
uint32_t address = ~0;
|
||||
if (FILE *fp = fopen(filename, "rb"); fp) {
|
||||
fseek(fp, offset, SEEK_SET);
|
||||
if (BYTE buf[4]; fread(buf, 1, sizeof buf, fp) == sizeof buf) {
|
||||
address =
|
||||
buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
|
||||
if (array<BYTE, 4> buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) {
|
||||
address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
DWORD bcm_host_get_peripheral_address(void)
|
||||
uint32_t bcm_host_get_peripheral_address()
|
||||
{
|
||||
DWORD address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
|
||||
uint32_t address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
|
||||
if (address == 0) {
|
||||
address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
|
||||
}
|
||||
address = (address == (DWORD)~0) ? 0x20000000 : address;
|
||||
#if 0
|
||||
printf("Peripheral address : 0x%lx\n", address);
|
||||
#endif
|
||||
address = (address == (uint32_t)~0) ? 0x20000000 : address;
|
||||
return address;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
// Assume the Raspberry Pi series and estimate the address from CPU
|
||||
DWORD bcm_host_get_peripheral_address(void)
|
||||
uint32_t bcm_host_get_peripheral_address()
|
||||
{
|
||||
char buf[1024];
|
||||
size_t len = sizeof(buf);
|
||||
array<char, 1024> buf;
|
||||
size_t len = buf.size();
|
||||
DWORD address;
|
||||
|
||||
if (sysctlbyname("hw.model", buf, &len, NULL, 0) ||
|
||||
strstr(buf, "ARM1176JZ-S") != buf) {
|
||||
if (sysctlbyname("hw.model", buf.data(), &len, NULL, 0) ||
|
||||
strstr(buf, "ARM1176JZ-S") != buf.data()) {
|
||||
// Failed to get CPU model || Not BCM2835
|
||||
// use the address of BCM283[67]
|
||||
address = 0x3f000000;
|
||||
@ -79,7 +75,7 @@ DWORD bcm_host_get_peripheral_address(void)
|
||||
printf("Peripheral address : 0x%lx\n", address);
|
||||
return address;
|
||||
}
|
||||
#endif // __NetBSD__
|
||||
#endif
|
||||
|
||||
bool GPIOBUS::Init(mode_e mode)
|
||||
{
|
||||
@ -91,11 +87,11 @@ bool GPIOBUS::Init(mode_e mode)
|
||||
#else
|
||||
int i;
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
struct epoll_event ev;
|
||||
epoll_event ev = {};
|
||||
#endif
|
||||
|
||||
// Get the base address
|
||||
baseaddr = (DWORD)bcm_host_get_peripheral_address();
|
||||
baseaddr = (uint32_t)bcm_host_get_peripheral_address();
|
||||
|
||||
// Open /dev/mem
|
||||
int fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
@ -232,7 +228,6 @@ bool GPIOBUS::Init(mode_e mode)
|
||||
|
||||
// epoll initialization
|
||||
epfd = epoll_create(1);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = EPOLLIN | EPOLLPRI;
|
||||
ev.data.fd = selevreq.fd;
|
||||
epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev);
|
||||
@ -1021,20 +1016,17 @@ int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
|
||||
//---------------------------------------------------------------------------
|
||||
bool GPIOBUS::PollSelectEvent()
|
||||
{
|
||||
// clear errno
|
||||
errno = 0;
|
||||
struct epoll_event epev;
|
||||
struct gpioevent_data gpev;
|
||||
|
||||
if (epoll_wait(epfd, &epev, 1, -1) <= 0) {
|
||||
LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__)
|
||||
if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) {
|
||||
LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
|
||||
LOGWARN("%s read failed", __PRETTY_FUNCTION__)
|
||||
return false;
|
||||
}
|
||||
if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
|
||||
LOGWARN("%s read failed", __PRETTY_FUNCTION__)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1054,7 +1046,7 @@ void GPIOBUS::ClearSelectEvent()
|
||||
// Signal table
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const int GPIOBUS::SignalTable[19] = {
|
||||
const array<int, 19> GPIOBUS::SignalTable = {
|
||||
PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3,
|
||||
PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP,
|
||||
PIN_SEL,PIN_ATN, PIN_RST, PIN_ACK,
|
||||
@ -1077,9 +1069,9 @@ void GPIOBUS::MakeTable(void)
|
||||
array<bool, 256> tblParity;
|
||||
|
||||
// Create parity table
|
||||
for (int i = 0; i < 0x100; i++) {
|
||||
auto bits = (DWORD)i;
|
||||
DWORD parity = 0;
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
uint32_t bits = i;
|
||||
uint32_t parity = 0;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
parity ^= bits & 1;
|
||||
bits >>= 1;
|
||||
@ -1090,11 +1082,16 @@ void GPIOBUS::MakeTable(void)
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
// Mask and setting data generation
|
||||
memset(tblDatMsk, 0xff, sizeof(tblDatMsk));
|
||||
memset(tblDatSet, 0x00, sizeof(tblDatSet));
|
||||
for (int i = 0; i < 0x100; i++) {
|
||||
for (auto& tbl : tblDatMsk) {
|
||||
tbl.fill(-1);
|
||||
}
|
||||
for (auto& tbl : tblDatSet) {
|
||||
tbl.fill(0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
// Bit string for inspection
|
||||
auto bits = (DWORD)i;
|
||||
uint32_t bits = i;
|
||||
|
||||
// Get parity
|
||||
if (tblParity[i]) {
|
||||
@ -1119,14 +1116,11 @@ void GPIOBUS::MakeTable(void)
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Mask and setting data generation
|
||||
memset(tblDatMsk, 0x00, sizeof(tblDatMsk));
|
||||
memset(tblDatSet, 0x00, sizeof(tblDatSet));
|
||||
for (int i = 0; i < 0x100; i++) {
|
||||
// bit string for inspection
|
||||
DWORD bits = (DWORD)i;
|
||||
for (uint32_t i = 0; i < 0x100; i++) {
|
||||
// Bit string for inspection
|
||||
uint32_t bits = i;
|
||||
|
||||
// get parity
|
||||
// Get parity
|
||||
if (tblParity[i]) {
|
||||
bits |= (1 << 8);
|
||||
}
|
||||
@ -1137,8 +1131,8 @@ void GPIOBUS::MakeTable(void)
|
||||
#endif
|
||||
|
||||
// Create GPIO register information
|
||||
DWORD gpclr = 0;
|
||||
DWORD gpset = 0;
|
||||
uint32_t gpclr = 0;
|
||||
uint32_t gpset = 0;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
if (bits & 1) {
|
||||
gpset |= (1 << pintbl[j]);
|
||||
@ -1400,11 +1394,10 @@ void GPIOBUS::DrvConfig(DWORD drive)
|
||||
BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
|
||||
{
|
||||
// Selection Phase
|
||||
if (GetPinRaw(raw_data, PIN_SEL))
|
||||
{
|
||||
if(GetPinRaw(raw_data, PIN_IO)){
|
||||
if (GetPinRaw(raw_data, PIN_SEL)) {
|
||||
if(GetPinRaw(raw_data, PIN_IO)) {
|
||||
return BUS::phase_t::reselection;
|
||||
}else{
|
||||
} else{
|
||||
return BUS::phase_t::selection;
|
||||
}
|
||||
}
|
||||
@ -1415,7 +1408,7 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
DWORD mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00;
|
||||
int mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00;
|
||||
mci |= GetPinRaw(raw_data, PIN_CD) ? 0x02 : 0x00;
|
||||
mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00;
|
||||
return GetPhase(mci);
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "scsi.h"
|
||||
#include <array>
|
||||
|
||||
#ifdef __linux
|
||||
#include <linux/gpio.h>
|
||||
@ -40,6 +41,8 @@
|
||||
#error Invalid connection type or none specified
|
||||
#endif
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Signal control logic and pin assignment customization
|
||||
@ -455,7 +458,9 @@ private:
|
||||
|
||||
mode_e actmode = mode_e::TARGET; // Operation mode
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
uint32_t baseaddr = 0; // Base address
|
||||
#endif
|
||||
|
||||
int rpitype = 0; // Type of Raspberry Pi
|
||||
|
||||
@ -463,7 +468,9 @@ private:
|
||||
|
||||
volatile uint32_t *pads = nullptr; // PADS register
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
volatile uint32_t *level = nullptr; // GPIO input level
|
||||
#endif
|
||||
|
||||
volatile uint32_t *irpctl = nullptr; // Interrupt control register
|
||||
|
||||
@ -477,11 +484,13 @@ private:
|
||||
|
||||
volatile uint32_t giccpmr; // GICC priority setting
|
||||
|
||||
#if !defined(__x86_64__) && !defined(__X86__)
|
||||
volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register
|
||||
#endif
|
||||
|
||||
volatile uint32_t *gicc = nullptr; // GIC CPU interface register
|
||||
|
||||
DWORD gpfsel[4]; // GPFSEL0-4 backup values
|
||||
array<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
|
||||
|
||||
uint32_t signals = 0; // All bus signals
|
||||
|
||||
@ -492,15 +501,15 @@ private:
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
#if SIGNAL_CONTROL_MODE == 0
|
||||
DWORD tblDatMsk[3][256]; // Data mask table
|
||||
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
|
||||
|
||||
DWORD tblDatSet[3][256]; // Data setting table
|
||||
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
|
||||
#else
|
||||
DWORD tblDatMsk[256]; // Data mask table
|
||||
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
|
||||
|
||||
DWORD tblDatSet[256]; // Table setting table
|
||||
array<uint32_t, 256> tblDatSet = {}; // Table setting table
|
||||
#endif
|
||||
|
||||
static const int SignalTable[19]; // signal table
|
||||
static const array<int, 19> SignalTable; // signal table
|
||||
};
|
||||
|
||||
|
@ -17,155 +17,154 @@ using namespace std;
|
||||
|
||||
Localizer::Localizer()
|
||||
{
|
||||
// Positional string arguments are %1, %2, %3
|
||||
Add(ERROR_AUTHENTICATION, "en", "Authentication failed");
|
||||
Add(ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
|
||||
Add(ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades");
|
||||
Add(ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
|
||||
Add(ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
|
||||
Add(ERROR_OPERATION, "en", "Unknown operation");
|
||||
Add(ERROR_OPERATION, "de", "Unbekannte Operation");
|
||||
Add(ERROR_OPERATION, "sv", "Okänd operation");
|
||||
Add(ERROR_OPERATION, "fr", "Opération inconnue");
|
||||
Add(ERROR_OPERATION, "es", "Operación desconocida");
|
||||
Add(ERROR_LOG_LEVEL, "en", "Invalid log level %1");
|
||||
Add(ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
|
||||
Add(ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
|
||||
Add(ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
|
||||
Add(ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
|
||||
Add(ERROR_MISSING_FILENAME, "en", "Missing filename");
|
||||
Add(ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
|
||||
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
|
||||
Add(ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
|
||||
Add(ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "de", "Gerätetyp %1 erfordert einen Dateinamen");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "sv", "Enhetstypen %1 kräver ett filnamn");
|
||||
Add(ERROR_DEVICE_MISSING_FILENAME, "es", "El tipo de dispositivo %1 requiere un nombre de archivo");
|
||||
Add(ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
|
||||
Add(ERROR_IMAGE_IN_USE, "sv", "Skivbildsfilen '%1' används redan av id %2, enhetsnummer %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "en", "Can't create image file info for '%1'");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "de", "Image-Datei-Information für '%1' kann nicht erzeugt werden");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "sv", "Kunde ej skapa skivbildsfilsinfo för '%1'");
|
||||
Add(ERROR_IMAGE_FILE_INFO, "es", "No se puede crear información de archivo de imagen para '%1'");
|
||||
Add(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
|
||||
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
|
||||
Add(ERROR_RESERVED_ID, "sv", "Enhets-id %1 är reserverat");
|
||||
Add(ERROR_RESERVED_ID, "fr", "ID de périphérique %1 réservée");
|
||||
Add(ERROR_RESERVED_ID, "es", "El ID de dispositivo %1 está reservado");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för id %1 som ej existerar");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "fr", "Commande pour ID %1 non-existant");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "es", "Comando para ID %1 no existente");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "sv", "Kommando för id %1, enhetsnummer %2 som ej existerar");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "fr", "Command pour ID %1, unité %2 non-existant");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "es", "Tipo de dispositivo desconocido %1");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "fr", "Type de périphérique requis pour extension inconnue du fichier '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "es", "Tipo de dispositivo requerido para la extensión desconocida del archivo '%1'");
|
||||
Add(ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
|
||||
Add(ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
|
||||
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2");
|
||||
Add(ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
|
||||
Add(ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
|
||||
Add(ERROR_DETACH, "en", "Couldn't detach device");
|
||||
Add(ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
|
||||
Add(ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten");
|
||||
Add(ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo");
|
||||
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
|
||||
Add(ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
|
||||
Add(ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
|
||||
Add(ERROR_EJECT_REQUIRED, "fr", "Media déjà existant doit d'abord être éjecté");
|
||||
Add(ERROR_EJECT_REQUIRED, "es", "El medio existente debe ser expulsado primero");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "fr", "Une fois défini, le nom de périphérique ne peut plus être changé");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "es", "Una vez establecido el nombre del dispositivo ya no se puede cambiar");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "sv", "Saknar root-rättigheter för att kunna stänga av eller starta om systemet");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "fr", "Permissions root manquantes pour extinction ou redémarrage");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "es", "Falta el permiso de root para el apagado o el reinicio");
|
||||
Add(ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2");
|
||||
Add(ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
|
||||
Add(ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
|
||||
Add(ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
|
||||
Add(ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
|
||||
Add(ERROR_BLOCK_SIZE, "es", "Tamaño de bloque inválido %1 bytes");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
|
||||
Add(ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller");
|
||||
Add(ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
|
||||
Add(ERROR_SCSI_CONTROLLER, "sv", "Kunde ej skapa SCSI-gränssnitt");
|
||||
Add(ERROR_SCSI_CONTROLLER, "es", "No se ha podido crear el controlador SCSI");
|
||||
Add(ERROR_INVALID_ID, "en", "Invalid device ID %1 (0-%2)");
|
||||
Add(ERROR_INVALID_ID, "de", "Ungültige Geräte-ID %1 (0-%2)");
|
||||
Add(ERROR_INVALID_ID, "sv", "Ogiltigt enhets-id %1 (0-%2)");
|
||||
Add(ERROR_INVALID_ID, "es", "ID de dispositivo inválido %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)");
|
||||
Add(ERROR_INVALID_LUN, "es", "LUN invalido %1 (0-%2)");
|
||||
Add(ERROR_LUN0, "en", "LUN 0 cannot be detached as long as there is still another LUN");
|
||||
Add(ERROR_LUN0, "de", "LUN 0 kann nicht entfernt werden, solange noch eine andere LUN existiert");
|
||||
Add(ERROR_LUN0, "sv", "Enhetsnummer 0 kan ej bli frånkopplat så länge som andra enhetsnummer är anslutna");
|
||||
Add(ERROR_LUN0, "es", "El LUN 0 no se puede desconectar mientras haya otro LUN");
|
||||
Add(ERROR_INITIALIZATION, "en", "Initialization of %1 device, ID %2, LUN %3 failed");
|
||||
Add(ERROR_INITIALIZATION, "de", "Initialisierung von %1-Gerät, ID %2, LUN %3 fehlgeschlagen");
|
||||
Add(ERROR_INITIALIZATION, "sv", "Kunde ej initialisera enheten %1 med id %2 och enhetsnummer %3");
|
||||
Add(ERROR_INITIALIZATION, "es", "La inicialización del dispositivo %1, ID %2, LUN %3 falló");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "en", "%1 operation denied, %2 isn't stoppable");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "de", "%1-Operation verweigert, %2 ist nicht stopbar");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "sv", "Operationen %1 nekades för att %2 inte kan stoppas");
|
||||
Add(ERROR_OPERATION_DENIED_STOPPABLE, "es", "%1 operación denegada, %2 no se puede parar");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "en", "%1 operation denied, %2 isn't removable");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "de", "%1-Operation verweigert, %2 ist nicht wechselbar");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "sv", "Operationen %1 nekades för att %2 inte är uttagbar(t)");
|
||||
Add(ERROR_OPERATION_DENIED_REMOVABLE, "es", "%1 operación denegada, %2 no es removible");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "en", "%1 operation denied, %2 isn't protectable");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "de", "%1-Operation verweigert, %2 ist nicht schützbar");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "sv", "Operationen %1 nekades för att %2 inte är skyddbar(t)");
|
||||
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "es", "%1 operación denegada, %2 no es protegible");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "en", "%1 operation denied, %2 isn't ready");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "sv", "Operationen %1 nekades för att %2 inte är redo");
|
||||
Add(ERROR_OPERATION_DENIED_READY, "es", "%1 operación denegada, %2 no está listo");
|
||||
Add(LocalizationKey::ERROR_AUTHENTICATION, "en", "Authentication failed");
|
||||
Add(LocalizationKey::ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
|
||||
Add(LocalizationKey::ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades");
|
||||
Add(LocalizationKey::ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
|
||||
Add(LocalizationKey::ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
|
||||
Add(LocalizationKey::ERROR_OPERATION, "en", "Unknown operation");
|
||||
Add(LocalizationKey::ERROR_OPERATION, "de", "Unbekannte Operation");
|
||||
Add(LocalizationKey::ERROR_OPERATION, "sv", "Okänd operation");
|
||||
Add(LocalizationKey::ERROR_OPERATION, "fr", "Opération inconnue");
|
||||
Add(LocalizationKey::ERROR_OPERATION, "es", "Operación desconocida");
|
||||
Add(LocalizationKey::ERROR_LOG_LEVEL, "en", "Invalid log level %1");
|
||||
Add(LocalizationKey::ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
|
||||
Add(LocalizationKey::ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
|
||||
Add(LocalizationKey::ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
|
||||
Add(LocalizationKey::ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
|
||||
Add(LocalizationKey::ERROR_MISSING_FILENAME, "en", "Missing filename");
|
||||
Add(LocalizationKey::ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
|
||||
Add(LocalizationKey::ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
|
||||
Add(LocalizationKey::ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
|
||||
Add(LocalizationKey::ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
|
||||
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
|
||||
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "de", "Gerätetyp %1 erfordert einen Dateinamen");
|
||||
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "sv", "Enhetstypen %1 kräver ett filnamn");
|
||||
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "es", "El tipo de dispositivo %1 requiere un nombre de archivo");
|
||||
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
|
||||
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
|
||||
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "sv", "Skivbildsfilen '%1' används redan av id %2, enhetsnummer %3");
|
||||
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
|
||||
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
|
||||
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "en", "Can't create image file info for '%1'");
|
||||
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "de", "Image-Datei-Information für '%1' kann nicht erzeugt werden");
|
||||
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "sv", "Kunde ej skapa skivbildsfilsinfo för '%1'");
|
||||
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "es", "No se puede crear información de archivo de imagen para '%1'");
|
||||
Add(LocalizationKey::ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
|
||||
Add(LocalizationKey::ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
|
||||
Add(LocalizationKey::ERROR_RESERVED_ID, "sv", "Enhets-id %1 är reserverat");
|
||||
Add(LocalizationKey::ERROR_RESERVED_ID, "fr", "ID de périphérique %1 réservée");
|
||||
Add(LocalizationKey::ERROR_RESERVED_ID, "es", "El ID de dispositivo %1 está reservado");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för id %1 som ej existerar");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "fr", "Commande pour ID %1 non-existant");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "es", "Comando para ID %1 no existente");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "sv", "Kommando för id %1, enhetsnummer %2 som ej existerar");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "fr", "Command pour ID %1, unité %2 non-existant");
|
||||
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2");
|
||||
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
|
||||
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
|
||||
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
|
||||
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
|
||||
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "es", "Tipo de dispositivo desconocido %1");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "fr", "Type de périphérique requis pour extension inconnue du fichier '%1'");
|
||||
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "es", "Tipo de dispositivo requerido para la extensión desconocida del archivo '%1'");
|
||||
Add(LocalizationKey::ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
|
||||
Add(LocalizationKey::ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
|
||||
Add(LocalizationKey::ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2");
|
||||
Add(LocalizationKey::ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
|
||||
Add(LocalizationKey::ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
|
||||
Add(LocalizationKey::ERROR_DETACH, "en", "Couldn't detach device");
|
||||
Add(LocalizationKey::ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
|
||||
Add(LocalizationKey::ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten");
|
||||
Add(LocalizationKey::ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo");
|
||||
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
|
||||
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
|
||||
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
|
||||
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "fr", "Media déjà existant doit d'abord être éjecté");
|
||||
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "es", "El medio existente debe ser expulsado primero");
|
||||
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
|
||||
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
|
||||
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
|
||||
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "fr", "Une fois défini, le nom de périphérique ne peut plus être changé");
|
||||
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "es", "Una vez establecido el nombre del dispositivo ya no se puede cambiar");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "sv", "Saknar root-rättigheter för att kunna stänga av eller starta om systemet");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "fr", "Permissions root manquantes pour extinction ou redémarrage");
|
||||
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "es", "Falta el permiso de root para el apagado o el reinicio");
|
||||
Add(LocalizationKey::ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
|
||||
Add(LocalizationKey::ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
|
||||
Add(LocalizationKey::ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
|
||||
Add(LocalizationKey::ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
|
||||
Add(LocalizationKey::ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE, "es", "Tamaño de bloque inválido %1 bytes");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
|
||||
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
|
||||
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller");
|
||||
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
|
||||
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "sv", "Kunde ej skapa SCSI-gränssnitt");
|
||||
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "es", "No se ha podido crear el controlador SCSI");
|
||||
Add(LocalizationKey::ERROR_INVALID_ID, "en", "Invalid device ID %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_ID, "de", "Ungültige Geräte-ID %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_ID, "sv", "Ogiltigt enhets-id %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_ID, "es", "ID de dispositivo inválido %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_INVALID_LUN, "es", "LUN invalido %1 (0-%2)");
|
||||
Add(LocalizationKey::ERROR_LUN0, "en", "LUN 0 cannot be detached as long as there is still another LUN");
|
||||
Add(LocalizationKey::ERROR_LUN0, "de", "LUN 0 kann nicht entfernt werden, solange noch eine andere LUN existiert");
|
||||
Add(LocalizationKey::ERROR_LUN0, "sv", "Enhetsnummer 0 kan ej bli frånkopplat så länge som andra enhetsnummer är anslutna");
|
||||
Add(LocalizationKey::ERROR_LUN0, "es", "El LUN 0 no se puede desconectar mientras haya otro LUN");
|
||||
Add(LocalizationKey::ERROR_INITIALIZATION, "en", "Initialization of %1 device, ID %2, LUN %3 failed");
|
||||
Add(LocalizationKey::ERROR_INITIALIZATION, "de", "Initialisierung von %1-Gerät, ID %2, LUN %3 fehlgeschlagen");
|
||||
Add(LocalizationKey::ERROR_INITIALIZATION, "sv", "Kunde ej initialisera enheten %1 med id %2 och enhetsnummer %3");
|
||||
Add(LocalizationKey::ERROR_INITIALIZATION, "es", "La inicialización del dispositivo %1, ID %2, LUN %3 falló");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "en", "%1 operation denied, %2 isn't stoppable");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "de", "%1-Operation verweigert, %2 ist nicht stopbar");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "sv", "Operationen %1 nekades för att %2 inte kan stoppas");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "es", "%1 operación denegada, %2 no se puede parar");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "en", "%1 operation denied, %2 isn't removable");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "de", "%1-Operation verweigert, %2 ist nicht wechselbar");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "sv", "Operationen %1 nekades för att %2 inte är uttagbar(t)");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "es", "%1 operación denegada, %2 no es removible");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "en", "%1 operation denied, %2 isn't protectable");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "de", "%1-Operation verweigert, %2 ist nicht schützbar");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "sv", "Operationen %1 nekades för att %2 inte är skyddbar(t)");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "es", "%1 operación denegada, %2 no es protegible");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "en", "%1 operation denied, %2 isn't ready");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "sv", "Operationen %1 nekades för att %2 inte är redo");
|
||||
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "es", "%1 operación denegada, %2 no está listo");
|
||||
}
|
||||
|
||||
void Localizer::Add(LocalizationKey key, const string& locale, string_view value)
|
||||
@ -200,7 +199,7 @@ string Localizer::Localize(LocalizationKey key, const string& locale, const stri
|
||||
|
||||
auto messages = it->second;
|
||||
if (messages.empty()) {
|
||||
return "Missing localization for enum value " + to_string(key);
|
||||
return "Missing localization for enum value " + to_string((int)key);
|
||||
}
|
||||
|
||||
string message = messages[key];
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
using namespace std; //NOSONAR Not relevant for rascsi
|
||||
|
||||
enum LocalizationKey {
|
||||
enum class LocalizationKey {
|
||||
ERROR_AUTHENTICATION,
|
||||
ERROR_OPERATION,
|
||||
ERROR_LOG_LEVEL,
|
||||
|
@ -71,7 +71,7 @@ DeviceFactory device_factory;
|
||||
ControllerManager controller_manager;
|
||||
RascsiImage rascsi_image;
|
||||
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
|
||||
SocketConnector socket_connector;
|
||||
const SocketConnector socket_connector;
|
||||
|
||||
void DetachAll();
|
||||
static void *MonThread(void *);
|
||||
@ -139,9 +139,8 @@ bool InitService(int port)
|
||||
}
|
||||
|
||||
// Create socket for monitor
|
||||
sockaddr_in server;
|
||||
sockaddr_in server = {};
|
||||
monsocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sin_family = PF_INET;
|
||||
server.sin_port = htons(port);
|
||||
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
@ -388,11 +387,11 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
const PbDeviceType type = pb_device.type();
|
||||
|
||||
if (controller_manager.GetDeviceByIdAndLun(id, unit) != nullptr) {
|
||||
return ReturnLocalizedError(context, ERROR_DUPLICATE_ID, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DUPLICATE_ID, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
if (unit >= AbstractController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX));
|
||||
if (unit >= ScsiController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX));
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
@ -400,10 +399,10 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
PrimaryDevice *device = device_factory.CreateDevice(type, filename, id);
|
||||
if (device == nullptr) {
|
||||
if (type == UNDEFINED) {
|
||||
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_TYPE, filename);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
|
||||
}
|
||||
else {
|
||||
return ReturnLocalizedError(context, ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,13 +433,13 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, PbDeviceType_Name(type));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, PbDeviceType_Name(type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,7 +447,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (file_support != nullptr && !device->IsRemovable() && filename.empty()) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
}
|
||||
|
||||
Filepath filepath;
|
||||
@ -461,7 +460,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
try {
|
||||
@ -475,7 +474,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
file_support->Open(filepath);
|
||||
@ -484,7 +483,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
catch(const io_exception& e) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
}
|
||||
|
||||
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
|
||||
@ -510,7 +509,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (!device->Init(params)) {
|
||||
device_factory.DeleteDevice(*device);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ctrl_mutex);
|
||||
@ -518,7 +517,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (!controller_manager.CreateScsiController(bus, device)) {
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_SCSI_CONTROLLER);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SCSI_CONTROLLER);
|
||||
}
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
@ -541,7 +540,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
|
||||
for (const Device *d : device_factory.GetAllDevices()) {
|
||||
// LUN 0 can only be detached if there is no other LUN anymore
|
||||
if (d->GetId() == device->GetId() && d->GetLun()) {
|
||||
return ReturnLocalizedError(context, ERROR_LUN0);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_LUN0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -561,7 +560,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
|
||||
if (!controller_manager.FindController(id)->DeleteDevice(device)) {
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_DETACH);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DETACH);
|
||||
}
|
||||
device_factory.DeleteDevice(*device);
|
||||
pthread_mutex_unlock(&ctrl_mutex);
|
||||
@ -575,16 +574,16 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
|
||||
bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device, Device *device, bool dryRun)
|
||||
{
|
||||
if (!device->IsRemoved()) {
|
||||
return ReturnLocalizedError(context, ERROR_EJECT_REQUIRED);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_EJECT_REQUIRED);
|
||||
}
|
||||
|
||||
if (!pb_device.vendor().empty() || !pb_device.product().empty() || !pb_device.revision().empty()) {
|
||||
return ReturnLocalizedError(context, ERROR_DEVICE_NAME_UPDATE);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
if (filename.empty()) {
|
||||
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
@ -599,11 +598,11 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
if (pb_device.block_size()) {
|
||||
if (disk != nullptr&& disk->IsSectorSizeConfigurable()) {
|
||||
if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) {
|
||||
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, device->GetType());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, device->GetType());
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,7 +613,7 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
string initial_filename = filepath.GetPath();
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
auto file_support = dynamic_cast<FileSupport *>(device);
|
||||
@ -627,14 +626,14 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
filepath.SetPath((rascsi_image.GetDefaultImageFolder() + "/" + filename).c_str());
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
file_support->Open(filepath);
|
||||
}
|
||||
}
|
||||
catch(const io_exception& e) { //NOSONAR This exception is handled properly
|
||||
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
}
|
||||
|
||||
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
|
||||
@ -711,19 +710,19 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
||||
|
||||
// Check the Controller Number
|
||||
if (id < 0) {
|
||||
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_ID);
|
||||
}
|
||||
if (id >= ControllerManager::DEVICE_MAX) {
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
|
||||
}
|
||||
|
||||
if (operation == ATTACH && reserved_ids.find(id) != reserved_ids.end()) {
|
||||
return ReturnLocalizedError(context, ERROR_RESERVED_ID, to_string(id));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_RESERVED_ID, to_string(id));
|
||||
}
|
||||
|
||||
// Check the Unit Number
|
||||
if (unit < 0 || unit >= AbstractController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX - 1));
|
||||
if (unit < 0 || unit >= ScsiController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX - 1));
|
||||
}
|
||||
|
||||
if (operation == ATTACH) {
|
||||
@ -732,13 +731,13 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
||||
|
||||
// Does the controller exist?
|
||||
if (!dryRun && controller_manager.FindController(id) == nullptr) {
|
||||
return ReturnLocalizedError(context, ERROR_NON_EXISTING_DEVICE, to_string(id));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_DEVICE, to_string(id));
|
||||
}
|
||||
|
||||
// Does the unit exist?
|
||||
PrimaryDevice *device = controller_manager.GetDeviceByIdAndLun(id, unit);
|
||||
if (device == nullptr) {
|
||||
return ReturnLocalizedError(context, ERROR_NON_EXISTING_UNIT, to_string(id), to_string(unit));
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_UNIT, to_string(id), to_string(unit));
|
||||
}
|
||||
|
||||
if (operation == DETACH) {
|
||||
@ -746,18 +745,18 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
||||
}
|
||||
|
||||
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
|
||||
}
|
||||
|
||||
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
|
||||
}
|
||||
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
|
||||
}
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_READY, device->GetType());
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_READY, device->GetType());
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
@ -824,7 +823,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
|
||||
break;
|
||||
|
||||
default:
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -915,8 +914,8 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
|
||||
unit = 0;
|
||||
}
|
||||
else if (!GetAsInt(id_spec.substr(0, separator_pos), id) || id < 0 || id > 7 ||
|
||||
!GetAsInt(id_spec.substr(separator_pos + 1), unit) || unit < 0 || unit >= AbstractController::LUN_MAX) {
|
||||
cerr << optarg << ": Invalid unit (0-" << (AbstractController::LUN_MAX - 1) << ")" << endl;
|
||||
!GetAsInt(id_spec.substr(separator_pos + 1), unit) || unit < 0 || unit >= ScsiController::LUN_MAX) {
|
||||
cerr << optarg << ": Invalid unit (0-" << (ScsiController::LUN_MAX - 1) << ")" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -925,7 +924,7 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
|
||||
|
||||
void ShutDown(const CommandContext& context, const string& mode) {
|
||||
if (mode.empty()) {
|
||||
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_MISSING);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -942,7 +941,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
|
||||
|
||||
// The root user has UID 0
|
||||
if (getuid()) {
|
||||
ReturnLocalizedError(context, ERROR_SHUTDOWN_PERMISSION);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -969,7 +968,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_INVALID);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1132,7 +1131,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||
command.set_operation(ATTACH);
|
||||
|
||||
Localizer localizer;
|
||||
CommandContext context(&socket_connector, &localizer, -1, locale);
|
||||
CommandContext context(socket_connector, localizer, -1, locale);
|
||||
if (!ProcessCmd(context, command)) {
|
||||
return false;
|
||||
}
|
||||
@ -1179,13 +1178,13 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
}
|
||||
|
||||
if (!access_token.empty() && access_token != GetParam(command, "token")) {
|
||||
return ReturnLocalizedError(context, ERROR_AUTHENTICATION, UNAUTHORIZED);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_AUTHENTICATION, UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if (!PbOperation_IsValid(command.operation())) {
|
||||
LOGERROR("Received unknown command with operation opcode %d", command.operation())
|
||||
|
||||
return ReturnLocalizedError(context, ERROR_OPERATION, UNKNOWN_OPERATION);
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION, UNKNOWN_OPERATION);
|
||||
}
|
||||
|
||||
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str())
|
||||
@ -1196,7 +1195,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
case LOG_LEVEL: {
|
||||
string log_level = GetParam(command, "level");
|
||||
if (bool status = SetLogLevel(log_level); !status) {
|
||||
ReturnLocalizedError(context, ERROR_LOG_LEVEL, log_level);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_LOG_LEVEL, log_level);
|
||||
}
|
||||
else {
|
||||
ReturnStatus(context);
|
||||
@ -1256,7 +1255,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
|
||||
case IMAGE_FILE_INFO: {
|
||||
if (string filename = GetParam(command, "file"); filename.empty()) {
|
||||
ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
}
|
||||
else {
|
||||
auto image_file = make_unique<PbImageFile>();
|
||||
@ -1267,7 +1266,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
socket_connector.SerializeMessage(context.fd, result);
|
||||
}
|
||||
else {
|
||||
ReturnLocalizedError(context, ERROR_IMAGE_FILE_INFO);
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_FILE_INFO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1340,9 +1339,10 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
|
||||
// Set up the monitor socket to receive commands
|
||||
listen(monsocket, 1);
|
||||
|
||||
Localizer localizer;
|
||||
|
||||
while (true) {
|
||||
Localizer localizer;
|
||||
CommandContext context(&socket_connector, &localizer, -1, "");
|
||||
CommandContext context(socket_connector, localizer, -1, "");
|
||||
|
||||
try {
|
||||
PbCommand command;
|
||||
|
@ -44,8 +44,7 @@ bool RascsiImage::CreateImageFolder(const CommandContext& context, const string&
|
||||
string folder = filename.substr(0, filename_start);
|
||||
|
||||
// Checking for existence first prevents an error if the top-level folder is a softlink
|
||||
struct stat st;
|
||||
if (stat(folder.c_str(), &st)) {
|
||||
if (struct stat st; stat(folder.c_str(), &st)) {
|
||||
std::error_code error;
|
||||
filesystem::create_directories(folder, error);
|
||||
if (error) {
|
||||
|
@ -24,7 +24,7 @@ PbDeviceProperties *RascsiResponse::GetDeviceProperties(const Device *device)
|
||||
{
|
||||
auto properties = make_unique<PbDeviceProperties>().release();
|
||||
|
||||
properties->set_luns(AbstractController::LUN_MAX);
|
||||
properties->set_luns(ScsiController::LUN_MAX);
|
||||
properties->set_read_only(device->IsReadOnly());
|
||||
properties->set_protectable(device->IsProtectable());
|
||||
properties->set_stoppable(device->IsStoppable());
|
||||
@ -56,7 +56,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
|
||||
type_properties->set_type(type);
|
||||
const PrimaryDevice *device = device_factory->CreateDevice(type, "", -1);
|
||||
type_properties->set_allocated_properties(GetDeviceProperties(device));
|
||||
device_factory->DeleteDevice(*device); //NOSONAR The alloced memory is managed by protobuf
|
||||
device_factory->DeleteDevice(*device); //NOSONAR The allocated memory is managed by protobuf
|
||||
}
|
||||
|
||||
void RascsiResponse::GetAllDeviceTypeProperties(PbDeviceTypesInfo& device_types_info)
|
||||
@ -92,7 +92,7 @@ void RascsiResponse::GetDevice(const Device *device, PbDevice *pb_device)
|
||||
status->set_removed(device->IsRemoved());
|
||||
status->set_locked(device->IsLocked());
|
||||
|
||||
if (device->SupportsParams()) { //NOSONAR The alloced memory is managed by protobuf
|
||||
if (device->SupportsParams()) { //NOSONAR The allocated memory is managed by protobuf
|
||||
for (const auto& [key, value] : device->GetParams()) {
|
||||
AddParam(*pb_device, key, value);
|
||||
}
|
||||
@ -111,7 +111,7 @@ void RascsiResponse::GetDevice(const Device *device, PbDevice *pb_device)
|
||||
GetImageFile(image_file, device->IsRemovable() && !device->IsReady() ? "" : filepath.GetPath());
|
||||
pb_device->set_allocated_file(image_file);
|
||||
}
|
||||
} //NOSONAR The alloced memory is managed by protobuf
|
||||
} //NOSONAR The allocated memory is managed by protobuf
|
||||
|
||||
bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filename) const
|
||||
{
|
||||
@ -123,8 +123,7 @@ bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filenam
|
||||
|
||||
image_file->set_read_only(access(f.c_str(), W_OK));
|
||||
|
||||
struct stat st; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
|
||||
if (!stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
|
||||
if (struct stat st; !stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
|
||||
image_file->set_size(st.st_size);
|
||||
return true;
|
||||
}
|
||||
@ -135,52 +134,57 @@ bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filenam
|
||||
|
||||
void RascsiResponse::GetAvailableImages(PbImageFilesInfo& image_files_info, string_view default_image_folder,
|
||||
const string& folder, const string& folder_pattern, const string& file_pattern, int scan_depth) {
|
||||
if (scan_depth-- < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
string folder_pattern_lower = folder_pattern;
|
||||
transform(folder_pattern_lower.begin(), folder_pattern_lower.end(), folder_pattern_lower.begin(), ::tolower);
|
||||
|
||||
string file_pattern_lower = file_pattern;
|
||||
transform(file_pattern_lower.begin(), file_pattern_lower.end(), file_pattern_lower.begin(), ::tolower);
|
||||
|
||||
if (scan_depth-- >= 0) {
|
||||
if (DIR *d = opendir(folder.c_str()); d) {
|
||||
const dirent *dir;
|
||||
while ((dir = readdir(d))) {
|
||||
bool is_supported_type = dir->d_type == DT_REG || dir->d_type == DT_DIR || dir->d_type == DT_LNK || dir->d_type == DT_BLK;
|
||||
if (is_supported_type && dir->d_name[0] != '.') {
|
||||
string name_lower = dir->d_name;
|
||||
if (!file_pattern.empty()) {
|
||||
transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
|
||||
}
|
||||
DIR *d = opendir(folder.c_str());
|
||||
if (d == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
string filename = folder + "/" + dir->d_name;
|
||||
|
||||
if (struct stat st; dir->d_type == DT_REG && !stat(filename.c_str(), &st)) {
|
||||
if (!st.st_size) {
|
||||
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
|
||||
continue;
|
||||
}
|
||||
} else if (dir->d_type == DT_LNK && stat(filename.c_str(), &st)) {
|
||||
LOGWARN("Symlink '%s' in image folder '%s' is broken", dir->d_name, folder.c_str())
|
||||
continue;
|
||||
} else if (dir->d_type == DT_DIR) {
|
||||
if (folder_pattern_lower.empty() || name_lower.find(folder_pattern_lower) != string::npos) {
|
||||
GetAvailableImages(image_files_info, default_image_folder, filename, folder_pattern,
|
||||
file_pattern, scan_depth);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_pattern_lower.empty() || name_lower.find(file_pattern_lower) != string::npos) {
|
||||
if (auto image_file = make_unique<PbImageFile>(); GetImageFile(image_file.get(), filename)) {
|
||||
GetImageFile(image_files_info.add_image_files(), filename.substr(default_image_folder.length() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
const dirent *dir;
|
||||
while ((dir = readdir(d))) {
|
||||
bool is_supported_type = dir->d_type == DT_REG || dir->d_type == DT_DIR || dir->d_type == DT_LNK || dir->d_type == DT_BLK;
|
||||
if (is_supported_type && dir->d_name[0] != '.') {
|
||||
string name_lower = dir->d_name;
|
||||
if (!file_pattern.empty()) {
|
||||
transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
string filename = folder + "/" + dir->d_name;
|
||||
|
||||
if (struct stat st; dir->d_type == DT_REG && !stat(filename.c_str(), &st)) {
|
||||
if (!st.st_size) {
|
||||
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
|
||||
continue;
|
||||
}
|
||||
} else if (dir->d_type == DT_LNK && stat(filename.c_str(), &st)) {
|
||||
LOGWARN("Symlink '%s' in image folder '%s' is broken", dir->d_name, folder.c_str())
|
||||
continue;
|
||||
} else if (dir->d_type == DT_DIR) {
|
||||
if (folder_pattern_lower.empty() || name_lower.find(folder_pattern_lower) != string::npos) {
|
||||
GetAvailableImages(image_files_info, default_image_folder, filename, folder_pattern,
|
||||
file_pattern, scan_depth);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_pattern_lower.empty() || name_lower.find(file_pattern_lower) != string::npos) {
|
||||
if (auto image_file = make_unique<PbImageFile>(); GetImageFile(image_file.get(), filename)) {
|
||||
GetImageFile(image_files_info.add_image_files(), filename.substr(default_image_folder.length() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
PbImageFilesInfo *RascsiResponse::GetAvailableImages(PbResult& result, const string& folder_pattern,
|
||||
@ -207,7 +211,7 @@ void RascsiResponse::GetAvailableImages(PbResult& result, PbServerInfo& server_i
|
||||
image_files_info->set_default_image_folder(rascsi_image->GetDefaultImageFolder());
|
||||
server_info.set_allocated_image_files_info(image_files_info);
|
||||
|
||||
result.set_status(true); //NOSONAR The alloced memory is managed by protobuf
|
||||
result.set_status(true); //NOSONAR The allocated memory is managed by protobuf
|
||||
}
|
||||
|
||||
PbReservedIdsInfo *RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids)
|
||||
@ -278,14 +282,14 @@ PbServerInfo *RascsiResponse::GetServerInfo(PbResult& result, const unordered_se
|
||||
auto server_info = make_unique<PbServerInfo>().release();
|
||||
|
||||
server_info->set_allocated_version_info(GetVersionInfo(result));
|
||||
server_info->set_allocated_log_level_info(GetLogLevelInfo(result, current_log_level)); //NOSONAR The alloced memory is managed by protobuf
|
||||
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info()); //NOSONAR The alloced memory is managed by protobuf
|
||||
server_info->set_allocated_log_level_info(GetLogLevelInfo(result, current_log_level)); //NOSONAR The allocated memory is managed by protobuf
|
||||
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info()); //NOSONAR The allocated memory is managed by protobuf
|
||||
GetAvailableImages(result, *server_info, folder_pattern, file_pattern, scan_depth);
|
||||
server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result));
|
||||
server_info->set_allocated_mapping_info(GetMappingInfo(result)); //NOSONAR The alloced memory is managed by protobuf
|
||||
GetDevices(*server_info); //NOSONAR The alloced memory is managed by protobuf
|
||||
server_info->set_allocated_mapping_info(GetMappingInfo(result)); //NOSONAR The allocated memory is managed by protobuf
|
||||
GetDevices(*server_info); //NOSONAR The allocated memory is managed by protobuf
|
||||
server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids));
|
||||
server_info->set_allocated_operation_info(GetOperationInfo(result, scan_depth)); //NOSONAR The alloced memory is managed by protobuf
|
||||
server_info->set_allocated_operation_info(GetOperationInfo(result, scan_depth)); //NOSONAR The allocated memory is managed by protobuf
|
||||
|
||||
result.set_status(true);
|
||||
|
||||
@ -461,11 +465,11 @@ PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth)
|
||||
PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation,
|
||||
const string& description) const
|
||||
{
|
||||
auto meta_data = make_unique<PbOperationMetaData>();
|
||||
auto meta_data = make_shared<PbOperationMetaData>();
|
||||
meta_data->set_server_side_name(PbOperation_Name(operation));
|
||||
meta_data->set_description(description);
|
||||
int ordinal = PbOperation_descriptor()->FindValueByName(PbOperation_Name(operation))->index();
|
||||
(*operation_info.mutable_operations())[ordinal] = *meta_data.release();
|
||||
(*operation_info.mutable_operations())[ordinal] = *meta_data.get();
|
||||
return &(*operation_info.mutable_operations())[ordinal];
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "rascsi_version.h"
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -380,7 +384,7 @@ int MessageIn()
|
||||
//---------------------------------------------------------------------------
|
||||
int TestUnitReady(int id)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
@ -392,9 +396,8 @@ int TestUnitReady(int id)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 6);
|
||||
cmd[0] = 0x00;
|
||||
if (!Command(cmd, 6)) {
|
||||
if (!Command(cmd.data(), 6)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -425,12 +428,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int RequestSense(int id, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -439,10 +441,9 @@ int RequestSense(int id, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 6);
|
||||
cmd[0] = 0x03;
|
||||
cmd[4] = 0xff;
|
||||
if (!Command(cmd, 6)) {
|
||||
if (!Command(cmd.data(), 6)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -486,12 +487,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int ModeSense(int id, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -500,11 +500,10 @@ int ModeSense(int id, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 6);
|
||||
cmd[0] = 0x1a;
|
||||
cmd[2] = 0x3f;
|
||||
cmd[4] = 0xff;
|
||||
if (!Command(cmd, 6)) {
|
||||
if (!Command(cmd.data(), 6)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -548,12 +547,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int Inquiry(int id, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -562,10 +560,9 @@ int Inquiry(int id, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 6);
|
||||
cmd[0] = 0x12;
|
||||
cmd[4] = 0xff;
|
||||
if (!Command(cmd, 6)) {
|
||||
if (!Command(cmd.data(), 6)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -609,12 +606,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int ReadCapacity(int id, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -623,9 +619,8 @@ int ReadCapacity(int id, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 10);
|
||||
cmd[0] = 0x25;
|
||||
if (!Command(cmd, 10)) {
|
||||
if (!Command(cmd.data(), 10)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -669,12 +664,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -683,7 +677,6 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 10);
|
||||
cmd[0] = 0x28;
|
||||
cmd[2] = (BYTE)(bstart >> 24);
|
||||
cmd[3] = (BYTE)(bstart >> 16);
|
||||
@ -691,7 +684,7 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
cmd[5] = (BYTE)bstart;
|
||||
cmd[7] = (BYTE)(blength >> 8);
|
||||
cmd[8] = (BYTE)blength;
|
||||
if (!Command(cmd, 10)) {
|
||||
if (!Command(cmd.data(), 10)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -734,12 +727,11 @@ exit:
|
||||
//---------------------------------------------------------------------------
|
||||
int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
{
|
||||
BYTE cmd[256];
|
||||
int count;
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
// Result code initialization
|
||||
result = 0;
|
||||
count = 0;
|
||||
int count = 0;
|
||||
|
||||
// SELECTION
|
||||
if (!Selection(id)) {
|
||||
@ -748,7 +740,6 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
}
|
||||
|
||||
// COMMAND
|
||||
memset(cmd, 0x00, 10);
|
||||
cmd[0] = 0x2a;
|
||||
cmd[2] = (BYTE)(bstart >> 24);
|
||||
cmd[3] = (BYTE)(bstart >> 16);
|
||||
@ -756,7 +747,7 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
cmd[5] = (BYTE)bstart;
|
||||
cmd[7] = (BYTE)(blength >> 8);
|
||||
cmd[8] = (BYTE)blength;
|
||||
if (!Command(cmd, 10)) {
|
||||
if (!Command(cmd.data(), 10)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
@ -833,6 +824,11 @@ int main(int argc, char* argv[])
|
||||
exit(EINVAL);
|
||||
}
|
||||
|
||||
#ifndef USE_SEL_EVENT_ENABLE
|
||||
cerr << "Error: No RaSCSI hardware support" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
|
||||
// Reset the SCSI bus
|
||||
Reset();
|
||||
|
||||
@ -910,15 +906,15 @@ int main(int argc, char* argv[])
|
||||
(buffer[2] << 8) | buffer[3];
|
||||
bnum++;
|
||||
printf("Number of blocks : %d Blocks\n", (int)bnum);
|
||||
printf("Block length : %d B\n", (int)bsiz);
|
||||
printf("Unit Capacity : %d MiB %d B\n",
|
||||
printf("Block length : %d Bytes\n", (int)bsiz);
|
||||
printf("Unit Capacity : %d MBytes %d Bytes\n",
|
||||
(int)(bsiz * bnum / 1024 / 1024),
|
||||
(int)(bsiz * bnum));
|
||||
|
||||
// Get the restore file size
|
||||
if (restore) {
|
||||
size = fio.GetFileSize();
|
||||
printf("Restore file size : %d B", (int)size);
|
||||
printf("Restore file size : %d bytes", (int)size);
|
||||
if (size > (off_t)(bsiz * bnum)) {
|
||||
printf("(WARNING : File size is larger than disk size)");
|
||||
} else if (size < (off_t)(bsiz * bnum)) {
|
||||
|
@ -20,10 +20,9 @@ using namespace rascsi_interface;
|
||||
int SocketConnector::ReadCommand(PbCommand& command, int socket) const
|
||||
{
|
||||
// Wait for connection
|
||||
sockaddr_in client;
|
||||
sockaddr client = {};
|
||||
socklen_t socklen = sizeof(client);
|
||||
memset(&client, 0, socklen);
|
||||
int fd = accept(socket, (sockaddr*)&client, &socklen);
|
||||
int fd = accept(socket, &client, &socklen);
|
||||
if (fd < 0) {
|
||||
throw io_exception("accept() failed");
|
||||
}
|
||||
|
@ -10,23 +10,114 @@
|
||||
#include "testing.h"
|
||||
#include "controllers/abstract_controller.h"
|
||||
|
||||
TEST(AbstractControllerTest, Reset)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::status);
|
||||
EXPECT_EQ(BUS::phase_t::status, controller.GetPhase());
|
||||
controller.Reset();
|
||||
EXPECT_TRUE(controller.IsBusFree());
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, SetGetStatus)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.SetStatus(0x1234);
|
||||
EXPECT_EQ(0x1234, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, SetPhase)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::selection);
|
||||
EXPECT_TRUE(controller.IsSelection());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::busfree);
|
||||
EXPECT_TRUE(controller.IsBusFree());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::command);
|
||||
EXPECT_TRUE(controller.IsCommand());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::status);
|
||||
EXPECT_TRUE(controller.IsStatus());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::datain);
|
||||
EXPECT_TRUE(controller.IsDataIn());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::dataout);
|
||||
EXPECT_TRUE(controller.IsDataOut());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgin);
|
||||
EXPECT_TRUE(controller.IsMsgIn());
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgout);
|
||||
EXPECT_TRUE(controller.IsMsgOut());
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, ProcessPhase)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::selection);
|
||||
EXPECT_CALL(controller, Selection()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::busfree);
|
||||
EXPECT_CALL(controller, BusFree()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::datain);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::dataout);
|
||||
EXPECT_CALL(controller, DataOut()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::command);
|
||||
EXPECT_CALL(controller, Command()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::status);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgin);
|
||||
EXPECT_CALL(controller, MsgIn()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::msgout);
|
||||
EXPECT_CALL(controller, MsgOut()).Times(1);
|
||||
controller.ProcessPhase();
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, DeviceLunLifeCycle)
|
||||
{
|
||||
const int ID = 1;
|
||||
const int LUN = 4;
|
||||
|
||||
MockAbstractController controller(ID);
|
||||
MockPrimaryDevice device;
|
||||
MockPrimaryDevice device1;
|
||||
MockPrimaryDevice device2;
|
||||
|
||||
device.SetLun(LUN);
|
||||
EXPECT_FALSE(controller.HasLuns());
|
||||
|
||||
device1.SetLun(LUN);
|
||||
device2.SetLun(32);
|
||||
|
||||
EXPECT_EQ(ID, controller.GetTargetId());
|
||||
EXPECT_TRUE(controller.AddDevice(&device));
|
||||
EXPECT_TRUE(controller.AddDevice(&device1));
|
||||
EXPECT_FALSE(controller.AddDevice(&device2));
|
||||
EXPECT_TRUE(controller.HasLuns());
|
||||
EXPECT_TRUE(controller.HasDeviceForLun(LUN));
|
||||
EXPECT_FALSE(controller.HasDeviceForLun(0));
|
||||
EXPECT_EQ(&device, controller.GetDeviceForLun(LUN));
|
||||
EXPECT_EQ(&device1, controller.GetDeviceForLun(LUN));
|
||||
EXPECT_EQ(nullptr, controller.GetDeviceForLun(0));
|
||||
EXPECT_TRUE(controller.DeleteDevice(&device));
|
||||
EXPECT_TRUE(controller.DeleteDevice(&device1));
|
||||
EXPECT_FALSE(controller.HasLuns());
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, ExtractInitiatorId)
|
||||
@ -45,9 +136,9 @@ TEST(AbstractControllerTest, GetOpcode)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.ctrl.cmd.resize(1);
|
||||
vector<int>& cmd = controller.InitCmd(2);
|
||||
|
||||
controller.ctrl.cmd[0] = 0x12;
|
||||
cmd[0] = 0x12;
|
||||
EXPECT_EQ(0x12, (int)controller.GetOpcode());
|
||||
}
|
||||
|
||||
@ -57,8 +148,16 @@ TEST(AbstractControllerTest, GetLun)
|
||||
|
||||
MockAbstractController controller(0);
|
||||
|
||||
controller.ctrl.cmd.resize(2);
|
||||
vector<int>& cmd = controller.InitCmd(2);
|
||||
|
||||
controller.ctrl.cmd[1] = LUN << 5;
|
||||
cmd[1] = LUN << 5;
|
||||
EXPECT_EQ(LUN, controller.GetLun());
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, Ctrl)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
|
||||
EXPECT_FALSE(controller.HasValidLength());
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "rascsi_version.h"
|
||||
#include "devices/device.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include <unordered_map>
|
||||
|
||||
TEST(DeviceFactoryTest, GetTypeForFile)
|
||||
{
|
||||
@ -101,12 +102,64 @@ TEST(DeviceFactoryTest, GetSectorSizes)
|
||||
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
|
||||
}
|
||||
|
||||
TEST(DeviceFactoryTest, GetExtensionMapping)
|
||||
{
|
||||
DeviceFactory device_factory;
|
||||
|
||||
unordered_map<string, PbDeviceType> mapping = device_factory.GetExtensionMapping();
|
||||
EXPECT_EQ(9, mapping.size());
|
||||
EXPECT_EQ(SCHD, mapping["hd1"]);
|
||||
EXPECT_EQ(SCHD, mapping["hds"]);
|
||||
EXPECT_EQ(SCHD, mapping["hda"]);
|
||||
EXPECT_EQ(SCHD, mapping["hdn"]);
|
||||
EXPECT_EQ(SCHD, mapping["hdi"]);
|
||||
EXPECT_EQ(SCHD, mapping["nhd"]);
|
||||
EXPECT_EQ(SCRM, mapping["hdr"]);
|
||||
EXPECT_EQ(SCMO, mapping["mos"]);
|
||||
EXPECT_EQ(SCCD, mapping["iso"]);
|
||||
}
|
||||
|
||||
TEST(DeviceFactoryTest, GetDefaultParams)
|
||||
{
|
||||
DeviceFactory device_factory;
|
||||
|
||||
unordered_map<string, string> params = device_factory.GetDefaultParams(SCHD);
|
||||
EXPECT_TRUE(params.empty());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCRM);
|
||||
EXPECT_TRUE(params.empty());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCMO);
|
||||
EXPECT_TRUE(params.empty());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCCD);
|
||||
EXPECT_TRUE(params.empty());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCHS);
|
||||
EXPECT_TRUE(params.empty());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCBR);
|
||||
EXPECT_EQ(2, params.size());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCDP);
|
||||
EXPECT_EQ(2, params.size());
|
||||
|
||||
params = device_factory.GetDefaultParams(SCLP);
|
||||
EXPECT_EQ(2, params.size());
|
||||
}
|
||||
|
||||
TEST(DeviceFactoryTest, UnknownDeviceType)
|
||||
{
|
||||
DeviceFactory device_factory;
|
||||
|
||||
PrimaryDevice *device = device_factory.CreateDevice(UNDEFINED, "test", -1);
|
||||
EXPECT_EQ(nullptr, device);
|
||||
PrimaryDevice *device1 = device_factory.CreateDevice(UNDEFINED, "test", -1);
|
||||
EXPECT_EQ(nullptr, device1);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
PrimaryDevice *device2 = device_factory.CreateDevice(SAHD, "test", -1);
|
||||
#pragma GCC diagnostic pop
|
||||
EXPECT_EQ(nullptr, device2);
|
||||
}
|
||||
|
||||
TEST(DeviceFactoryTest, SCHD_Device_Defaults)
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
class TestDevice final : public Device
|
||||
{
|
||||
FRIEND_TEST(DeviceTest, GetSetParams);
|
||||
FRIEND_TEST(DeviceTest, Params);
|
||||
FRIEND_TEST(DeviceTest, StatusCode);
|
||||
FRIEND_TEST(DeviceTest, Reset);
|
||||
FRIEND_TEST(DeviceTest, Start);
|
||||
@ -102,7 +102,7 @@ TEST(DeviceTest, ProductData)
|
||||
EXPECT_EQ("V P R ", device.GetPaddedName());
|
||||
}
|
||||
|
||||
TEST(DeviceTest, GetSetParams)
|
||||
TEST(DeviceTest, Params)
|
||||
{
|
||||
TestDevice device;
|
||||
unordered_map<string, string> params;
|
||||
|
@ -24,7 +24,7 @@ TEST(DiskTest, Rezero)
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRezero));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, FormatUnit)
|
||||
@ -34,7 +34,7 @@ TEST(DiskTest, FormatUnit)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
|
||||
|
||||
@ -42,10 +42,10 @@ TEST(DiskTest, FormatUnit)
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdFormat));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
controller.ctrl.cmd[1] = 0x10;
|
||||
controller.ctrl.cmd[4] = 1;
|
||||
cmd[1] = 0x10;
|
||||
cmd[4] = 1;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ TEST(DiskTest, ReassignBlocks)
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReassign));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, Seek)
|
||||
@ -73,7 +73,7 @@ TEST(DiskTest, Seek)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(10);
|
||||
vector<int>& cmd = controller.InitCmd(10);
|
||||
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
|
||||
<< "SEEK(6) must fail for a medium with 0 blocks";
|
||||
@ -89,17 +89,17 @@ TEST(DiskTest, Seek)
|
||||
disk.SetReady(true);
|
||||
|
||||
// Block count for SEEK(6)
|
||||
controller.ctrl.cmd[4] = 1;
|
||||
cmd[4] = 1;
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek6));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
controller.ctrl.cmd[4] = 0;
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
cmd[4] = 0;
|
||||
|
||||
// Block count for SEEK(10)
|
||||
controller.ctrl.cmd[5] = 1;
|
||||
cmd[5] = 1;
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek10));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, ReadCapacity)
|
||||
@ -109,7 +109,7 @@ TEST(DiskTest, ReadCapacity)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(16);
|
||||
vector<int>& cmd = controller.InitCmd(16);
|
||||
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
<< "Neithed READ CAPACITY(16) nor READ LONG(16)";
|
||||
@ -117,53 +117,53 @@ TEST(DiskTest, ReadCapacity)
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
|
||||
<< "READ CAPACITY(10) must fail because drive is not ready";
|
||||
// READ CAPACITY(16), not READ LONG(16)
|
||||
controller.ctrl.cmd[1] = 0x10;
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
<< "READ CAPACITY(16) must fail because drive is not ready";
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
cmd[1] = 0x00;
|
||||
|
||||
disk.SetReady(true);
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
|
||||
<< "READ CAPACITY(10) must fail because the medium has no capacity";
|
||||
// READ CAPACITY(16), not READ LONG(16)
|
||||
controller.ctrl.cmd[1] = 0x10;
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
<< "READ CAPACITY(16) must fail because the medium has no capacity";
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
cmd[1] = 0x00;
|
||||
|
||||
disk.SetBlockCount(0x12345678);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10));
|
||||
EXPECT_EQ(0x12, controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x34, controller.ctrl.buffer[1]);
|
||||
EXPECT_EQ(0x56, controller.ctrl.buffer[2]);
|
||||
EXPECT_EQ(0x77, controller.ctrl.buffer[3]);
|
||||
EXPECT_EQ(0x12, controller.GetBuffer()[0]);
|
||||
EXPECT_EQ(0x34, controller.GetBuffer()[1]);
|
||||
EXPECT_EQ(0x56, controller.GetBuffer()[2]);
|
||||
EXPECT_EQ(0x77, controller.GetBuffer()[3]);
|
||||
|
||||
disk.SetBlockCount(0x1234567887654321);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10));
|
||||
EXPECT_EQ(0xff, controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0xff, controller.ctrl.buffer[1]);
|
||||
EXPECT_EQ(0xff, controller.ctrl.buffer[2]);
|
||||
EXPECT_EQ(0xff, controller.ctrl.buffer[3]);
|
||||
EXPECT_EQ(0xff, controller.GetBuffer()[0]);
|
||||
EXPECT_EQ(0xff, controller.GetBuffer()[1]);
|
||||
EXPECT_EQ(0xff, controller.GetBuffer()[2]);
|
||||
EXPECT_EQ(0xff, controller.GetBuffer()[3]);
|
||||
|
||||
disk.SetSectorSizeInBytes(1024);
|
||||
// READ CAPACITY(16), not READ LONG(16)
|
||||
controller.ctrl.cmd[1] = 0x10;
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16));
|
||||
EXPECT_EQ(0x12, controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x34, controller.ctrl.buffer[1]);
|
||||
EXPECT_EQ(0x56, controller.ctrl.buffer[2]);
|
||||
EXPECT_EQ(0x78, controller.ctrl.buffer[3]);
|
||||
EXPECT_EQ(0x87, controller.ctrl.buffer[4]);
|
||||
EXPECT_EQ(0x65, controller.ctrl.buffer[5]);
|
||||
EXPECT_EQ(0x43, controller.ctrl.buffer[6]);
|
||||
EXPECT_EQ(0x20, controller.ctrl.buffer[7]);
|
||||
EXPECT_EQ(0x00, controller.ctrl.buffer[8]);
|
||||
EXPECT_EQ(0x00, controller.ctrl.buffer[9]);
|
||||
EXPECT_EQ(0x04, controller.ctrl.buffer[10]);
|
||||
EXPECT_EQ(0x00, controller.ctrl.buffer[11]);
|
||||
EXPECT_EQ(0x12, controller.GetBuffer()[0]);
|
||||
EXPECT_EQ(0x34, controller.GetBuffer()[1]);
|
||||
EXPECT_EQ(0x56, controller.GetBuffer()[2]);
|
||||
EXPECT_EQ(0x78, controller.GetBuffer()[3]);
|
||||
EXPECT_EQ(0x87, controller.GetBuffer()[4]);
|
||||
EXPECT_EQ(0x65, controller.GetBuffer()[5]);
|
||||
EXPECT_EQ(0x43, controller.GetBuffer()[6]);
|
||||
EXPECT_EQ(0x20, controller.GetBuffer()[7]);
|
||||
EXPECT_EQ(0x00, controller.GetBuffer()[8]);
|
||||
EXPECT_EQ(0x00, controller.GetBuffer()[9]);
|
||||
EXPECT_EQ(0x04, controller.GetBuffer()[10]);
|
||||
EXPECT_EQ(0x00, controller.GetBuffer()[11]);
|
||||
}
|
||||
|
||||
TEST(DiskTest, ReadWriteLong)
|
||||
@ -173,51 +173,51 @@ TEST(DiskTest, ReadWriteLong)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(16);
|
||||
vector<int>& cmd = controller.InitCmd(16);
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadLong10));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdWriteLong10));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
controller.ctrl.cmd[2] = 1;
|
||||
cmd[2] = 1;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
|
||||
<< "READ LONG(10) must fail because the capacity is exceeded";
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
|
||||
<< "WRITE LONG(10) must fail because the capacity is exceeded";
|
||||
// READ LONG(16), not READ CAPACITY(16)
|
||||
controller.ctrl.cmd[1] = 0x11;
|
||||
cmd[1] = 0x11;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
<< "READ LONG(16) must fail because the capacity is exceeded";
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
|
||||
<< "WRITE LONG(16) must fail because the capacity is exceeded";
|
||||
controller.ctrl.cmd[2] = 0;
|
||||
cmd[2] = 0;
|
||||
|
||||
controller.ctrl.cmd[7] = 1;
|
||||
cmd[7] = 1;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
|
||||
<< "READ LONG(10) must fail because it currently only supports 0 bytes transfer length";
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
|
||||
<< "WRITE LONG(10) must fail because it currently only supports 0 bytes transfer length";
|
||||
controller.ctrl.cmd[7] = 0;
|
||||
cmd[7] = 0;
|
||||
|
||||
// READ LONG(16), not READ CAPACITY(16)
|
||||
controller.ctrl.cmd[1] = 0x11;
|
||||
cmd[1] = 0x11;
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
cmd[1] = 0x00;
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdWriteLong16));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
controller.ctrl.cmd[13] = 1;
|
||||
cmd[13] = 1;
|
||||
// READ LONG(16), not READ CAPACITY(16)
|
||||
controller.ctrl.cmd[1] = 0x11;
|
||||
cmd[1] = 0x11;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
<< "READ LONG(16) must fail because it currently only supports 0 bytes transfer length";
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
cmd[1] = 0x00;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
|
||||
<< "WRITE LONG(16) must fail because it currently only supports 0 bytes transfer length";
|
||||
}
|
||||
@ -229,15 +229,15 @@ TEST(DiskTest, ReserveRelease)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
controller.InitCmd(6);
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReserve6));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRelease6));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, SendDiagnostic)
|
||||
@ -247,22 +247,22 @@ TEST(DiskTest, SendDiagnostic)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSendDiag));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
controller.ctrl.cmd[1] = 0x10;
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because PF bit is not supported";
|
||||
controller.ctrl.cmd[1] = 0;
|
||||
cmd[1] = 0;
|
||||
|
||||
controller.ctrl.cmd[3] = 1;
|
||||
cmd[3] = 1;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
|
||||
controller.ctrl.cmd[3] = 0;
|
||||
controller.ctrl.cmd[4] = 1;
|
||||
cmd[3] = 0;
|
||||
cmd[4] = 1;
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
|
||||
}
|
||||
@ -274,7 +274,7 @@ TEST(DiskTest, PreventAllowMediumRemoval)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
|
||||
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdRemoval), scsi_error_exception)
|
||||
<< "REMOVAL must fail because drive is not ready";
|
||||
@ -283,13 +283,13 @@ TEST(DiskTest, PreventAllowMediumRemoval)
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
EXPECT_FALSE(disk.IsLocked());
|
||||
|
||||
controller.ctrl.cmd[4] = 1;
|
||||
cmd[4] = 1;
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
EXPECT_TRUE(disk.IsLocked());
|
||||
}
|
||||
|
||||
@ -300,19 +300,19 @@ TEST(DiskTest, SynchronizeCache)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(10);
|
||||
controller.InitCmd(10);
|
||||
|
||||
EXPECT_CALL(disk, FlushCache()).Times(1);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSynchronizeCache10));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
|
||||
controller.ctrl.cmd.resize(16);
|
||||
controller.InitCmd(16);
|
||||
|
||||
EXPECT_CALL(disk, FlushCache()).Times(1);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSynchronizeCache16));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, ReadDefectData)
|
||||
@ -322,11 +322,11 @@ TEST(DiskTest, ReadDefectData)
|
||||
|
||||
controller.AddDevice(&disk);
|
||||
|
||||
controller.ctrl.cmd.resize(10);
|
||||
controller.InitCmd(10);
|
||||
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadDefectData10));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, SectorSize)
|
||||
|
@ -27,11 +27,11 @@ TEST(ModePagesTest, ModePageDevice_AddModePages)
|
||||
MockModePageDevice device;
|
||||
cdb[2] = 0x3f;
|
||||
|
||||
EXPECT_EQ(0, device.AddModePages(cdb, buf.data(), 0)) << "Allocation length was not limited";
|
||||
EXPECT_EQ(1, device.AddModePages(cdb, buf.data(), 1)) << "Allocation length was not limited";
|
||||
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, 0)) << "Allocation length was not limited";
|
||||
EXPECT_EQ(1, device.AddModePages(cdb, buf, 0, 1)) << "Allocation length was not limited";
|
||||
|
||||
cdb[2] = 0x00;
|
||||
EXPECT_THROW(device.AddModePages(cdb, buf.data(), 12), scsi_error_exception) << "Data for non-existing mode page 0 were returned";
|
||||
EXPECT_THROW(device.AddModePages(cdb, buf, 0, 12), scsi_error_exception) << "Data for non-existing mode page 0 were returned";
|
||||
}
|
||||
|
||||
TEST(ModePagesTest, SCSIHD_SetUpModePages)
|
||||
@ -83,9 +83,8 @@ TEST(ModePagesTest, SCSICD_SetUpModePages)
|
||||
TEST(ModePagesTest, SCSIMO_SetUpModePages)
|
||||
{
|
||||
map<int, vector<byte>> mode_pages;
|
||||
unordered_map<uint64_t, Geometry> geometries;
|
||||
const unordered_set<uint32_t> sector_sizes;
|
||||
MockSCSIMO device(sector_sizes, geometries);
|
||||
MockSCSIMO device(sector_sizes);
|
||||
device.SetUpModePages(mode_pages, 0x3f, false);
|
||||
|
||||
EXPECT_EQ(6, mode_pages.size()) << "Unexpected number of mode pages";
|
||||
@ -117,7 +116,7 @@ TEST(ModePagesTest, ModeSelect)
|
||||
|
||||
// PF (vendor-specific parameter format)
|
||||
cdb[1] = 0x00;
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH, 0), scsi_error_exception)
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH, 0), scsi_error_exception)
|
||||
<< "Vendor-specific parameters are not supported";
|
||||
|
||||
// PF (standard parameter format)
|
||||
@ -126,20 +125,20 @@ TEST(ModePagesTest, ModeSelect)
|
||||
buf[9] = 0x00;
|
||||
buf[10] = 0x02;
|
||||
buf[11] = 0x00;
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH, 256), scsi_error_exception)
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH, 256), scsi_error_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Page 0
|
||||
buf[LENGTH] = 0x00;
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH + 2, 512), scsi_error_exception)
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_error_exception)
|
||||
<< "Unsupported page 0 was not rejected";
|
||||
|
||||
// Page 3 (Format Device Page)
|
||||
buf[LENGTH] = 0x03;
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH + 2, 512), scsi_error_exception)
|
||||
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_error_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Match the requested to the current sector size
|
||||
buf[LENGTH + 12] = 0x02;
|
||||
scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH + 2, 512);
|
||||
scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ TEST(PrimaryDeviceTest, TestUnitReady)
|
||||
device.SetReady(true);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdTestUnitReady));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, Inquiry)
|
||||
@ -73,9 +73,9 @@ TEST(PrimaryDeviceTest, Inquiry)
|
||||
|
||||
device.SetController(&controller);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[4] = 255;
|
||||
cmd[4] = 255;
|
||||
|
||||
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
|
||||
return device.HandleInquiry(device_type::PROCESSOR, scsi_level::SPC_3, false);
|
||||
@ -83,18 +83,18 @@ TEST(PrimaryDeviceTest, Inquiry)
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(0x7F, controller.ctrl.buffer[0]) << "Invalid LUN was not reported";
|
||||
EXPECT_EQ(0x7F, controller.GetBuffer()[0]) << "Invalid LUN was not reported";
|
||||
|
||||
EXPECT_TRUE(controller.AddDevice(&device));
|
||||
EXPECT_FALSE(controller.AddDevice(&device)) << "Duplicate LUN was not rejected";
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(device_type::PROCESSOR, (device_type)controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x00, controller.ctrl.buffer[1]) << "Device was not reported as non-removable";
|
||||
EXPECT_EQ(scsi_level::SPC_3, (scsi_level)controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
EXPECT_EQ(device_type::PROCESSOR, (device_type)controller.GetBuffer()[0]);
|
||||
EXPECT_EQ(0x00, controller.GetBuffer()[1]) << "Device was not reported as non-removable";
|
||||
EXPECT_EQ(scsi_level::SPC_3, (scsi_level)controller.GetBuffer()[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller.GetBuffer()[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1f, controller.GetBuffer()[4]) << "Wrong additional data size";
|
||||
|
||||
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
|
||||
return device.HandleInquiry(device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, true);
|
||||
@ -102,29 +102,29 @@ TEST(PrimaryDeviceTest, Inquiry)
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller.ctrl.buffer[0]);
|
||||
EXPECT_EQ(0x80, controller.ctrl.buffer[1]) << "Device was not reported as removable";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.ctrl.buffer[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller.GetBuffer()[0]);
|
||||
EXPECT_EQ(0x80, controller.GetBuffer()[1]) << "Device was not reported as removable";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.GetBuffer()[2]) << "Wrong SCSI level";
|
||||
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.GetBuffer()[3]) << "Wrong response level";
|
||||
EXPECT_EQ(0x1F, controller.GetBuffer()[4]) << "Wrong additional data size";
|
||||
|
||||
controller.ctrl.cmd[1] = 0x01;
|
||||
cmd[1] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported";
|
||||
|
||||
controller.ctrl.cmd[2] = 0x01;
|
||||
cmd[2] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
|
||||
|
||||
controller.ctrl.cmd[1] = 0x00;
|
||||
controller.ctrl.cmd[2] = 0x00;
|
||||
cmd[1] = 0x00;
|
||||
cmd[2] = 0x00;
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[4] = 1;
|
||||
cmd[4] = 1;
|
||||
EXPECT_CALL(device, InquiryInternal()).Times(1);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
|
||||
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size";
|
||||
EXPECT_EQ(1, controller.ctrl.length) << "Wrong ALLOCATION LENGTH handling";
|
||||
EXPECT_EQ(0x1F, controller.GetBuffer()[4]) << "Wrong additional data size";
|
||||
EXPECT_EQ(1, controller.GetLength()) << "Wrong ALLOCATION LENGTH handling";
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, RequestSense)
|
||||
@ -134,9 +134,9 @@ TEST(PrimaryDeviceTest, RequestSense)
|
||||
|
||||
controller.AddDevice(&device);
|
||||
|
||||
controller.ctrl.cmd.resize(6);
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[4] = 255;
|
||||
cmd[4] = 255;
|
||||
|
||||
device.SetReady(false);
|
||||
EXPECT_THROW(device.Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
|
||||
@ -144,7 +144,7 @@ TEST(PrimaryDeviceTest, RequestSense)
|
||||
device.SetReady(true);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdRequestSense));
|
||||
EXPECT_EQ(0, controller.ctrl.status);
|
||||
EXPECT_EQ(0, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, ReportLuns)
|
||||
@ -163,13 +163,13 @@ TEST(PrimaryDeviceTest, ReportLuns)
|
||||
controller.AddDevice(&device2);
|
||||
EXPECT_TRUE(controller.HasDeviceForLun(LUN2));
|
||||
|
||||
controller.ctrl.cmd.resize(10);
|
||||
vector<int>& cmd = controller.InitCmd(10);
|
||||
// ALLOCATION LENGTH
|
||||
controller.ctrl.cmd[9] = 255;
|
||||
cmd[9] = 255;
|
||||
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
EXPECT_TRUE(device1.Dispatch(scsi_command::eCmdReportLuns));
|
||||
const BYTE *buffer = controller.ctrl.buffer;
|
||||
const vector<BYTE>& buffer = controller.GetBuffer();
|
||||
EXPECT_EQ(0x00, buffer[0]) << "Wrong data length";
|
||||
EXPECT_EQ(0x00, buffer[1]) << "Wrong data length";
|
||||
EXPECT_EQ(0x00, buffer[2]) << "Wrong data length";
|
||||
@ -191,7 +191,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
|
||||
EXPECT_EQ(0x00, buffer[22]) << "Wrong LUN2 number";
|
||||
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
|
||||
|
||||
controller.ctrl.cmd[2] = 0x01;
|
||||
cmd[2] = 0x01;
|
||||
EXPECT_THROW(device1.Dispatch(scsi_command::eCmdReportLuns), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
|
||||
}
|
||||
|
||||
@ -202,7 +202,7 @@ TEST(PrimaryDeviceTest, UnknownCommand)
|
||||
|
||||
controller.AddDevice(&device);
|
||||
|
||||
controller.ctrl.cmd.resize(1);
|
||||
controller.InitCmd(1);
|
||||
EXPECT_FALSE(device.Dispatch((scsi_command)0xFF));
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,12 @@ TEST(ScsiCommandUtilTest, GetInt16)
|
||||
EXPECT_EQ(0x1234, GetInt16(v, 0));
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, GetInt24)
|
||||
{
|
||||
vector<int> v = { 0x12, 0x34, 0x56 };
|
||||
EXPECT_EQ(0x123456, GetInt24(v, 0));
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, GetInt32)
|
||||
{
|
||||
vector<int> v = { 0x12, 0x34, 0x56, 0x78 };
|
||||
@ -66,11 +72,6 @@ TEST(ScsiCommandUtilTest, GetInt64)
|
||||
|
||||
TEST(ScsiCommandUtilTest, SetInt16)
|
||||
{
|
||||
vector<BYTE> buf(2);
|
||||
SetInt16(buf.data(), 0x1234);
|
||||
EXPECT_EQ(0x12, buf[0]);
|
||||
EXPECT_EQ(0x34, buf[1]);
|
||||
|
||||
vector<byte> v(2);
|
||||
SetInt16(v, 0, 0x1234);
|
||||
EXPECT_EQ(byte{0x12}, v[0]);
|
||||
@ -80,7 +81,7 @@ TEST(ScsiCommandUtilTest, SetInt16)
|
||||
TEST(ScsiCommandUtilTest, SetInt32)
|
||||
{
|
||||
vector<BYTE> buf(4);
|
||||
SetInt32(buf.data(), 0x12345678);
|
||||
SetInt32(buf, 0, 0x12345678);
|
||||
EXPECT_EQ(0x12, buf[0]);
|
||||
EXPECT_EQ(0x34, buf[1]);
|
||||
EXPECT_EQ(0x56, buf[2]);
|
||||
@ -97,7 +98,7 @@ TEST(ScsiCommandUtilTest, SetInt32)
|
||||
TEST(ScsiCommandUtilTest, SetInt64)
|
||||
{
|
||||
vector<BYTE> buf(8);
|
||||
SetInt64(buf.data(), 0x1234567887654321);
|
||||
SetInt64(buf, 0, 0x1234567887654321);
|
||||
EXPECT_EQ(0x12, buf[0]);
|
||||
EXPECT_EQ(0x34, buf[1]);
|
||||
EXPECT_EQ(0x56, buf[2]);
|
||||
|
@ -10,14 +10,6 @@
|
||||
#include "testing.h"
|
||||
#include "controllers/scsi_controller.h"
|
||||
|
||||
TEST(ScsiControllerTest, Reset)
|
||||
{
|
||||
MockScsiController controller(nullptr, 0);
|
||||
|
||||
EXPECT_CALL(controller, SetPhase(BUS::phase_t::busfree)).Times(1);
|
||||
controller.Reset();
|
||||
}
|
||||
|
||||
TEST(ScsiControllerTest, GetMaxLuns)
|
||||
{
|
||||
MockScsiController controller(nullptr, 0);
|
||||
|
@ -20,16 +20,23 @@
|
||||
#include "devices/scsimo.h"
|
||||
#include "devices/host_services.h"
|
||||
|
||||
class MockAbstractController final : public AbstractController
|
||||
class MockAbstractController final : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
|
||||
{
|
||||
FRIEND_TEST(AbstractControllerTest, Reset);
|
||||
FRIEND_TEST(AbstractControllerTest, SetPhase);
|
||||
FRIEND_TEST(AbstractControllerTest, ProcessPhase);
|
||||
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
|
||||
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
|
||||
FRIEND_TEST(AbstractControllerTest, GetOpcode);
|
||||
FRIEND_TEST(AbstractControllerTest, GetLun);
|
||||
FRIEND_TEST(AbstractControllerTest, Ctrl);
|
||||
|
||||
public:
|
||||
|
||||
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(int, GetEffectiveLun, (), (const override));
|
||||
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
|
||||
MOCK_METHOD(int, GetInitiatorId, (), (const override));
|
||||
MOCK_METHOD(void, SetUnit, (int), ());
|
||||
MOCK_METHOD(void, Connect, (int, BUS *), ());
|
||||
MOCK_METHOD(void, Status, (), ());
|
||||
MOCK_METHOD(void, DataIn, (), ());
|
||||
MOCK_METHOD(void, DataOut, (), ());
|
||||
@ -38,60 +45,15 @@ public:
|
||||
MOCK_METHOD(void, Command, (), ());
|
||||
MOCK_METHOD(void, MsgIn, (), ());
|
||||
MOCK_METHOD(void, MsgOut, (), ());
|
||||
MOCK_METHOD(void, Send, (), ());
|
||||
MOCK_METHOD(bool, XferMsg, (int), ());
|
||||
MOCK_METHOD(bool, XferIn, (BYTE *), ());
|
||||
MOCK_METHOD(bool, XferOut, (bool), ());
|
||||
MOCK_METHOD(void, ReceiveBytes, (), ());
|
||||
MOCK_METHOD(void, Execute, (), ());
|
||||
MOCK_METHOD(void, FlushUnit, (), ());
|
||||
MOCK_METHOD(void, Receive, (), ());
|
||||
MOCK_METHOD(bool, HasUnit, (), (const override));
|
||||
MOCK_METHOD(void, SetByteTransfer, (bool), (override));
|
||||
MOCK_METHOD(void, ScheduleShutdown, (rascsi_shutdown_mode), (override));
|
||||
MOCK_METHOD(void, SetPhase, (BUS::phase_t), (override));
|
||||
MOCK_METHOD(void, Reset, (), (override));
|
||||
|
||||
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
|
||||
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
|
||||
FRIEND_TEST(AbstractControllerTest, GetOpcode);
|
||||
FRIEND_TEST(AbstractControllerTest, GetLun);
|
||||
|
||||
explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id) {}
|
||||
explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id, 32) {}
|
||||
~MockAbstractController() override = default;
|
||||
|
||||
int GetMaxLuns() const override { return 32; }
|
||||
};
|
||||
|
||||
class MockScsiController final : public ScsiController
|
||||
{
|
||||
public:
|
||||
|
||||
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
|
||||
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
|
||||
MOCK_METHOD(int, GetInitiatorId, (), (const override));
|
||||
MOCK_METHOD(void, SetUnit, (int), ());
|
||||
MOCK_METHOD(void, Connect, (int, BUS *), ());
|
||||
MOCK_METHOD(void, Status, (), ());
|
||||
MOCK_METHOD(void, DataIn, (), ());
|
||||
MOCK_METHOD(void, DataOut, (), ());
|
||||
MOCK_METHOD(void, BusFree, (), ());
|
||||
MOCK_METHOD(void, Selection, (), ());
|
||||
MOCK_METHOD(void, Command, (), ());
|
||||
MOCK_METHOD(void, MsgIn, (), ());
|
||||
MOCK_METHOD(void, MsgOut, (), ());
|
||||
MOCK_METHOD(void, Send, (), ());
|
||||
MOCK_METHOD(bool, XferMsg, (int), ());
|
||||
MOCK_METHOD(bool, XferIn, (BYTE *), ());
|
||||
MOCK_METHOD(bool, XferOut, (bool), ());
|
||||
MOCK_METHOD(void, ReceiveBytes, (), ());
|
||||
MOCK_METHOD(void, Execute, (), ());
|
||||
MOCK_METHOD(void, FlushUnit, (), ());
|
||||
MOCK_METHOD(void, Receive, (), ());
|
||||
MOCK_METHOD(bool, HasUnit, (), (const override));
|
||||
MOCK_METHOD(void, SetPhase, (BUS::phase_t), (override));
|
||||
MOCK_METHOD(void, Sleep, (), ());
|
||||
|
||||
FRIEND_TEST(PrimaryDeviceTest, TestUnitReady);
|
||||
FRIEND_TEST(PrimaryDeviceTest, Inquiry);
|
||||
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
|
||||
@ -109,6 +71,12 @@ public:
|
||||
FRIEND_TEST(DiskTest, SynchronizeCache);
|
||||
FRIEND_TEST(DiskTest, ReadDefectData);
|
||||
|
||||
public:
|
||||
|
||||
MOCK_METHOD(void, Status, (), ());
|
||||
MOCK_METHOD(void, DataIn, (), ());
|
||||
MOCK_METHOD(void, DataOut, (), ());
|
||||
|
||||
using ScsiController::ScsiController;
|
||||
};
|
||||
|
||||
@ -131,14 +99,12 @@ class MockModePageDevice final : public ModePageDevice
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages);
|
||||
|
||||
public:
|
||||
|
||||
MockModePageDevice() : ModePageDevice("test") {}
|
||||
~MockModePageDevice() override = default;
|
||||
|
||||
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
|
||||
MOCK_METHOD(int, ModeSense6, (const vector<int>&, BYTE *, int), (const override));
|
||||
MOCK_METHOD(int, ModeSense10, (const vector<int>&, BYTE *, int), (const override));
|
||||
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&, int), (const override));
|
||||
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<BYTE>&, int), (const override));
|
||||
|
||||
void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
|
||||
// Return dummy data for other pages than page 0
|
||||
@ -177,25 +143,21 @@ class MockSCSIHD_NEC final : public SCSIHD_NEC //NOSONAR Ignore inheritance hier
|
||||
|
||||
MOCK_METHOD(void, FlushCache, (), (override));
|
||||
|
||||
MockSCSIHD_NEC() = default;
|
||||
~MockSCSIHD_NEC() override = default;
|
||||
using SCSIHD_NEC::SCSIHD_NEC;
|
||||
};
|
||||
|
||||
class MockSCSICD final : public SCSICD
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages);
|
||||
|
||||
explicit MockSCSICD(const unordered_set<uint32_t>& sector_sizes) : SCSICD(sector_sizes) {}
|
||||
~MockSCSICD() override = default;
|
||||
using SCSICD::SCSICD;
|
||||
};
|
||||
|
||||
class MockSCSIMO final : public SCSIMO
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages);
|
||||
|
||||
MockSCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries)
|
||||
: SCSIMO(sector_sizes, geometries) {}
|
||||
~MockSCSIMO() override = default;
|
||||
using SCSIMO::SCSIMO;
|
||||
};
|
||||
|
||||
class MockHostServices final : public HostServices
|
||||
|
Loading…
Reference in New Issue
Block a user