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:
Uwe Seimet 2022-10-01 17:56:06 +02:00 committed by GitHub
parent 78bab77f4b
commit 255a6e139f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1742 additions and 1783 deletions

View File

@ -16,12 +16,12 @@ class Localizer;
struct CommandContext 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) {} : connector(c), localizer(l), fd(f), locale(s) {}
~CommandContext() = default; ~CommandContext() = default;
SocketConnector *connector; const SocketConnector& connector;
const Localizer *localizer; const Localizer& localizer;
int fd; int fd;
std::string locale; std::string locale;
}; };

View File

@ -28,26 +28,27 @@ void command_util::ParseParameters(PbDeviceDefinition& device, const string& par
return; 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. // Old style parameters, for backwards compatibility only.
// Only one of these parameters will be used by rascsi, depending on the device type. // 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); AddParam(device, "file", params);
if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") { if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") {
AddParam(device, "interfaces", params); 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) 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) const string& arg1, const string& arg2, const string& arg3)
{ {
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3); return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
} }
bool command_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key, bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
const PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3) PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
{ {
// For the logfile always use English // 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); false);
} }
bool command_util::ReturnStatus(const CommandContext& context, bool status, const string& msg, 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 // Do not log twice if logging has already been done in the localized error handling above
if (log && !status && !msg.empty()) { 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_status(status);
result.set_error_code(error_code); result.set_error_code(error_code);
result.set_msg(msg); result.set_msg(msg);
context.connector->SerializeMessage(context.fd, result); context.connector.SerializeMessage(context.fd, result);
} }
return status; return status;

View File

@ -27,10 +27,10 @@ namespace command_util
void AddParam(PbCommand&, const string&, string_view); void AddParam(PbCommand&, const string&, string_view);
void AddParam(PbDevice&, const string&, string_view); void AddParam(PbDevice&, const string&, string_view);
void AddParam(PbDeviceDefinition&, 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& = ""); const string& = "");
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "", bool ReturnLocalizedError(const CommandContext&, LocalizationKey, PbErrorCode, const string& = "",
const string& = "", const string& = ""); const string& = "", const string& = "");
bool ReturnStatus(const CommandContext&, bool = true, 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);
} }

View File

@ -10,9 +10,74 @@
#include "abstract_controller.h" #include "abstract_controller.h"
#include "devices/primary_device.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 { PrimaryDevice *AbstractController::GetDeviceForLun(int lun) const {
const auto& it = ctrl.luns.find(lun); const auto& it = luns.find(lun);
return it == ctrl.luns.end() ? nullptr : it->second; 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) bool AbstractController::AddDevice(PrimaryDevice *device)
@ -25,7 +90,7 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
return false; return false;
} }
ctrl.luns[device->GetLun()] = device; luns[device->GetLun()] = device;
device->SetController(this); device->SetController(this);
return true; return true;
@ -33,12 +98,12 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
bool AbstractController::DeleteDevice(const 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 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 int AbstractController::ExtractInitiatorId(int id_data) const

View File

@ -16,14 +16,21 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
using namespace std; //NOSONAR Not relevant for rascsi
class PrimaryDevice; class PrimaryDevice;
class AbstractController class AbstractController
{ {
public: friend class PrimaryDevice;
friend class ScsiController;
// Maximum number of logical units BUS::phase_t phase = BUS::phase_t::busfree;
static const int LUN_MAX = 32;
// Logical units of this device controller mapped to their LUN numbers
unordered_map<int, PrimaryDevice *> luns;
public:
enum class rascsi_shutdown_mode { enum class rascsi_shutdown_mode {
NONE, NONE,
@ -33,32 +40,23 @@ public:
}; };
using ctrl_t = struct _ctrl_t { using ctrl_t = struct _ctrl_t {
// General vector<int> cmd; // Command data, dynamically allocated per received command
BUS::phase_t phase = BUS::phase_t::busfree; // Transition phase
// commands
std::vector<int> cmd; // Command data, dynamically allocated per received command
uint32_t status; // Status data uint32_t status; // Status data
int message; // Message data int message; // Message data
// Transfer // Transfer
BYTE *buffer; // Transfer data buffer vector<BYTE> buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size
uint32_t blocks; // Number of transfer blocks uint32_t blocks; // Number of transfer blocks
uint64_t next; // Next record uint64_t next; // Next record
uint32_t offset; // Transfer offset uint32_t offset; // Transfer offset
uint32_t length; // Transfer remaining length 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; virtual ~AbstractController() = default;
AbstractController(AbstractController&) = delete; AbstractController(AbstractController&) = delete;
AbstractController& operator=(const AbstractController&) = delete; AbstractController& operator=(const AbstractController&) = delete;
virtual void SetPhase(BUS::phase_t) = 0;
virtual void BusFree() = 0; virtual void BusFree() = 0;
virtual void Selection() = 0; virtual void Selection() = 0;
virtual void Command() = 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, 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; scsi_defs::status = scsi_defs::status::CHECK_CONDITION) = 0;
virtual void Reset() = 0; virtual void Reset();
virtual int GetInitiatorId() const = 0; virtual int GetInitiatorId() const = 0;
virtual void SetByteTransfer(bool) = 0; virtual void SetByteTransfer(bool) = 0;
// Get requested LUN based on IDENTIFY message, with LUN from the CDB as fallback // Get requested LUN based on IDENTIFY message, with LUN from the CDB as fallback
virtual int GetEffectiveLun() const = 0; virtual int GetEffectiveLun() const = 0;
virtual int GetMaxLuns() const = 0;
virtual void ScheduleShutdown(rascsi_shutdown_mode) = 0; virtual void ScheduleShutdown(rascsi_shutdown_mode) = 0;
int GetTargetId() const { return target_id; } int GetTargetId() const { return target_id; }
int GetMaxLuns() const { return max_luns; }
bool HasLuns() const { return !luns.empty(); }
PrimaryDevice *GetDeviceForLun(int) const; PrimaryDevice *GetDeviceForLun(int) const;
bool AddDevice(PrimaryDevice *); bool AddDevice(PrimaryDevice *);
@ -91,17 +89,46 @@ public:
bool HasDeviceForLun(int) const; bool HasDeviceForLun(int) const;
int ExtractInitiatorId(int id_data) const; int ExtractInitiatorId(int id_data) const;
// TODO Do not expose internal data void AllocateBuffer(size_t);
ctrl_t* GetCtrl() { return &ctrl; } vector<BYTE>& GetBuffer() { return ctrl.buffer; }
size_t GetBufferSize() const { return ctrl.buffer.size(); }
int target_id; uint32_t GetStatus() const { return ctrl.status; }
void SetStatus(uint32_t s) { ctrl.status = s; }
uint32_t GetLength() const { return ctrl.length; }
protected: protected:
scsi_defs::scsi_command GetOpcode() const { return (scsi_defs::scsi_command)ctrl.cmd[0]; } scsi_defs::scsi_command GetOpcode() const { return (scsi_defs::scsi_command)ctrl.cmd[0]; }
int GetLun() const { return (ctrl.cmd[1] >> 5) & 0x07; } 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; shared_ptr<BUS> bus;
int max_luns;
ctrl_t ctrl = {}; ctrl_t ctrl = {};
ctrl_t* GetCtrl() { return &ctrl; }
}; };

View File

@ -10,8 +10,6 @@
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI device controller ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "log.h" #include "log.h"
@ -29,42 +27,26 @@
using namespace scsi_defs; 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 initial buffer size will default to either the default buffer size OR
// the size of an Ethernet message, whichever is larger. // the size of an Ethernet message, whichever is larger.
ctrl.bufsize = std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN); AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN));
ctrl.buffer = new BYTE[ctrl.bufsize];
}
ScsiController::~ScsiController()
{
delete[] ctrl.buffer;
} }
void ScsiController::Reset() void ScsiController::Reset()
{ {
SetPhase(BUS::phase_t::busfree); AbstractController::Reset();
ctrl.status = 0x00;
ctrl.message = 0x00;
execstart = 0; execstart = 0;
ctrl.blocks = 0;
ctrl.next = 0;
ctrl.offset = 0;
ctrl.length = 0;
identified_lun = -1; identified_lun = -1;
scsi.atnmsg = false; scsi.atnmsg = false;
scsi.msc = 0; scsi.msc = 0;
memset(scsi.msb.data(), 0x00, scsi.msb.size()); scsi.msb = {};
is_byte_transfer = false; is_byte_transfer = false;
bytes_to_transfer = 0; bytes_to_transfer = 0;
// Reset all LUNs
for (const auto& [lun, device] : ctrl.luns) {
device->Reset();
}
} }
BUS::phase_t ScsiController::Process(int id) BUS::phase_t ScsiController::Process(int id)
@ -82,7 +64,7 @@ BUS::phase_t ScsiController::Process(int id)
// Reset the bus // Reset the bus
bus->Reset(); bus->Reset();
return ctrl.phase; return GetPhase();
} }
if (id != UNKNOWN_INITIATOR_ID) { if (id != UNKNOWN_INITIATOR_ID) {
@ -95,44 +77,7 @@ BUS::phase_t ScsiController::Process(int id)
initiator_id = id; initiator_id = id;
try { try {
// Phase processing ProcessPhase();
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;
}
} }
catch(const scsi_error_exception&) { catch(const scsi_error_exception&) {
// Any exception should have been handled during the phase processing // Any exception should have been handled during the phase processing
@ -146,12 +91,12 @@ BUS::phase_t ScsiController::Process(int id)
BusFree(); BusFree();
} }
return ctrl.phase; return GetPhase();
} }
void ScsiController::BusFree() void ScsiController::BusFree()
{ {
if (ctrl.phase != BUS::phase_t::busfree) { if (!IsBusFree()) {
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__) LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__)
SetPhase(BUS::phase_t::busfree); SetPhase(BUS::phase_t::busfree);
@ -163,7 +108,7 @@ void ScsiController::BusFree()
bus->SetBSY(false); bus->SetBSY(false);
// Initialize status and message // Initialize status and message
ctrl.status = 0x00; SetStatus(0);
ctrl.message = 0x00; ctrl.message = 0x00;
// Initialize ATN message reception status // Initialize ATN message reception status
@ -211,14 +156,14 @@ void ScsiController::BusFree()
void ScsiController::Selection() void ScsiController::Selection()
{ {
if (ctrl.phase != BUS::phase_t::selection) { if (!IsSelection()) {
// A different device controller was selected // A different device controller was selected
if (int id = 1 << GetTargetId(); ((int)bus->GetDAT() & id) == 0) { if (int id = 1 << GetTargetId(); ((int)bus->GetDAT() & id) == 0) {
return; return;
} }
// Abort if there is no LUN for this controller // Abort if there is no LUN for this controller
if (ctrl.luns.empty()) { if (!HasLuns()) {
return; return;
} }
@ -244,7 +189,7 @@ void ScsiController::Selection()
void ScsiController::Command() void ScsiController::Command()
{ {
if (ctrl.phase != BUS::phase_t::command) { if (!IsCommand()) {
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__) LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__)
SetPhase(BUS::phase_t::command); SetPhase(BUS::phase_t::command);
@ -253,8 +198,8 @@ void ScsiController::Command()
bus->SetCD(true); bus->SetCD(true);
bus->SetIO(false); bus->SetIO(false);
int actual_count = bus->CommandHandShake(ctrl.buffer); int actual_count = bus->CommandHandShake(GetBuffer().data());
int command_byte_count = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]); int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
// If not able to receive all, move to the status phase // If not able to receive all, move to the status phase
if (actual_count != command_byte_count) { if (actual_count != command_byte_count) {
@ -264,12 +209,12 @@ void ScsiController::Command()
return; return;
} }
ctrl.cmd.resize(command_byte_count); InitCmd(command_byte_count);
// Command data transfer // Command data transfer
stringstream s; stringstream s;
for (int i = 0; i < command_byte_count; i++) { 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]; s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
} }
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str()) LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
@ -287,13 +232,13 @@ void ScsiController::Execute()
SetPhase(BUS::phase_t::execute); SetPhase(BUS::phase_t::execute);
// Initialization for data transfer // Initialization for data transfer
ctrl.offset = 0; ResetOffset();
ctrl.blocks = 1; ctrl.blocks = 1;
execstart = SysTimer::GetTimerLow(); execstart = SysTimer::GetTimerLow();
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE // Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if (GetOpcode() != scsi_command::eCmdRequestSense) { if (GetOpcode() != scsi_command::eCmdRequestSense) {
ctrl.status = 0; SetStatus(0);
} }
int lun = GetEffectiveLun(); int lun = GetEffectiveLun();
@ -339,13 +284,13 @@ void ScsiController::Execute()
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, device->GetId()) 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() void ScsiController::Status()
{ {
if (ctrl.phase != BUS::phase_t::status) { if (!IsStatus()) {
// Minimum execution time // Minimum execution time
if (execstart > 0) { if (execstart > 0) {
Sleep(); Sleep();
@ -353,7 +298,7 @@ void ScsiController::Status()
SysTimer::SleepUsec(5); 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); SetPhase(BUS::phase_t::status);
@ -363,10 +308,10 @@ void ScsiController::Status()
bus->SetIO(true); bus->SetIO(true);
// Data transfer is 1 byte x 1 block // Data transfer is 1 byte x 1 block
ctrl.offset = 0; ResetOffset();
ctrl.length = 1; ctrl.length = 1;
ctrl.blocks = 1; ctrl.blocks = 1;
ctrl.buffer[0] = (BYTE)ctrl.status; GetBuffer()[0] = (BYTE)GetStatus();
return; return;
} }
@ -376,7 +321,7 @@ void ScsiController::Status()
void ScsiController::MsgIn() void ScsiController::MsgIn()
{ {
if (ctrl.phase != BUS::phase_t::msgin) { if (!IsMsgIn()) {
LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__) LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__)
SetPhase(BUS::phase_t::msgin); SetPhase(BUS::phase_t::msgin);
@ -386,9 +331,9 @@ void ScsiController::MsgIn()
bus->SetIO(true); bus->SetIO(true);
// length, blocks are already set // length, blocks are already set
assert(ctrl.length > 0); assert(HasValidLength());
assert(ctrl.blocks > 0); assert(ctrl.blocks > 0);
ctrl.offset = 0; ResetOffset();
return; return;
} }
@ -400,14 +345,14 @@ void ScsiController::MsgOut()
{ {
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId()) LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId())
if (ctrl.phase != BUS::phase_t::msgout) { if (!IsMsgOut()) {
LOGTRACE("Message Out Phase") LOGTRACE("Message Out Phase")
// process the IDENTIFY message // process the IDENTIFY message
if (ctrl.phase == BUS::phase_t::selection) { if (IsSelection()) {
scsi.atnmsg = true; scsi.atnmsg = true;
scsi.msc = 0; scsi.msc = 0;
memset(scsi.msb.data(), 0x00, scsi.msb.size()); scsi.msb = {};
} }
SetPhase(BUS::phase_t::msgout); SetPhase(BUS::phase_t::msgout);
@ -417,7 +362,7 @@ void ScsiController::MsgOut()
bus->SetIO(false); bus->SetIO(false);
// Data transfer is 1 byte x 1 block // Data transfer is 1 byte x 1 block
ctrl.offset = 0; ResetOffset();
ctrl.length = 1; ctrl.length = 1;
ctrl.blocks = 1; ctrl.blocks = 1;
@ -429,14 +374,14 @@ void ScsiController::MsgOut()
void ScsiController::DataIn() void ScsiController::DataIn()
{ {
if (ctrl.phase != BUS::phase_t::datain) { if (!IsDataIn()) {
// Minimum execution time // Minimum execution time
if (execstart > 0) { if (execstart > 0) {
Sleep(); Sleep();
} }
// If the length is 0, go to the status phase // If the length is 0, go to the status phase
if (ctrl.length == 0) { if (!HasValidLength()) {
Status(); Status();
return; return;
} }
@ -451,7 +396,7 @@ void ScsiController::DataIn()
// length, blocks are already set // length, blocks are already set
assert(ctrl.blocks > 0); assert(ctrl.blocks > 0);
ctrl.offset = 0; ResetOffset();
return; return;
} }
@ -461,14 +406,14 @@ void ScsiController::DataIn()
void ScsiController::DataOut() void ScsiController::DataOut()
{ {
if (ctrl.phase != BUS::phase_t::dataout) { if (!IsDataOut()) {
// Minimum execution time // Minimum execution time
if (execstart > 0) { if (execstart > 0) {
Sleep(); Sleep();
} }
// If the length is 0, go to the status phase // If the length is 0, go to the status phase
if (ctrl.length == 0) { if (!HasValidLength()) {
Status(); Status();
return; return;
} }
@ -482,7 +427,7 @@ void ScsiController::DataOut()
bus->SetCD(false); bus->SetCD(false);
bus->SetIO(false); bus->SetIO(false);
ctrl.offset = 0; ResetOffset();
return; 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 // 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(); BusFree();
return; 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)); GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
} }
ctrl.status = (uint32_t)status; SetStatus((uint32_t)status);
ctrl.message = 0x00; ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__) LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__)
@ -533,13 +478,13 @@ void ScsiController::Send()
assert(!bus->GetREQ()); assert(!bus->GetREQ());
assert(bus->GetIO()); assert(bus->GetIO());
if (ctrl.length != 0) { if (HasValidLength()) {
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(ctrl.offset) + ", length " LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(ctrl.offset) + ", length "
+ to_string(ctrl.length)).c_str()) + 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 // 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. // 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); HasDeviceForLun(0) ? GetDeviceForLun(0)->GetSendDelay() : 0);
len != (int)ctrl.length) { len != (int)ctrl.length) {
// If you cannot send all, move to status phase // If you cannot send all, move to status phase
@ -547,9 +492,8 @@ void ScsiController::Send()
return; return;
} }
// offset and length UpdateOffsetAndLength();
ctrl.offset += ctrl.length;
ctrl.length = 0;
return; return;
} }
@ -558,9 +502,9 @@ void ScsiController::Send()
bool result = true; bool result = true;
// Processing after data collection (read/data-in only) // 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) // 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()) 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 // Continue sending if block !=0
if (ctrl.blocks != 0){ if (ctrl.blocks != 0){
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Continuing to send. Blocks: " + to_string(ctrl.blocks)).c_str()) 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); assert(ctrl.offset == 0);
return; return;
} }
// Move to next phase // Move to next phase
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), (int)ctrl.phase) LOGTRACE("%s Move to next phase: %s", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
switch (ctrl.phase) { switch (GetPhase()) {
// Message in phase // Message in phase
case BUS::phase_t::msgin: case BUS::phase_t::msgin:
// Completed sending response to extended message of IDENTIFY message // Completed sending response to extended message of IDENTIFY message
@ -607,7 +551,7 @@ void ScsiController::Send()
// Message in phase // Message in phase
ctrl.length = 1; ctrl.length = 1;
ctrl.blocks = 1; ctrl.blocks = 1;
ctrl.buffer[0] = (BYTE)ctrl.message; GetBuffer()[0] = (BYTE)ctrl.message;
MsgIn(); MsgIn();
break; break;
@ -631,20 +575,19 @@ void ScsiController::Receive()
assert(!bus->GetIO()); assert(!bus->GetIO());
// Length != 0 if received // Length != 0 if received
if (ctrl.length != 0) { if (HasValidLength()) {
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length) LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
// If not able to receive all, move to status phase // 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) { len != (int)ctrl.length) {
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, ctrl.length, len) LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, ctrl.length, len)
Error(sense_key::ABORTED_COMMAND); Error(sense_key::ABORTED_COMMAND);
return; return;
} }
// Offset and Length UpdateOffsetAndLength();
ctrl.offset += ctrl.length;
ctrl.length = 0;
return; return;
} }
@ -653,8 +596,8 @@ void ScsiController::Receive()
bool result = true; bool result = true;
// Processing after receiving data (by phase) // Processing after receiving data (by phase)
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase)) LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
switch (ctrl.phase) { switch (GetPhase()) {
case BUS::phase_t::dataout: case BUS::phase_t::dataout:
if (ctrl.blocks == 0) { if (ctrl.blocks == 0) {
// End with this buffer // End with this buffer
@ -666,7 +609,7 @@ void ScsiController::Receive()
break; break;
case BUS::phase_t::msgout: case BUS::phase_t::msgout:
ctrl.message = ctrl.buffer[0]; ctrl.message = GetBuffer()[0];
if (!XferMsg(ctrl.message)) { if (!XferMsg(ctrl.message)) {
// Immediately free the bus if message output fails // Immediately free the bus if message output fails
BusFree(); BusFree();
@ -689,13 +632,13 @@ void ScsiController::Receive()
// Continue to receive if block !=0 // Continue to receive if block !=0
if (ctrl.blocks != 0) { if (ctrl.blocks != 0) {
assert(ctrl.length > 0); assert(HasValidLength());
assert(ctrl.offset == 0); assert(ctrl.offset == 0);
return; return;
} }
// Move to next phase // Move to next phase
switch (ctrl.phase) { switch (GetPhase()) {
case BUS::phase_t::command: case BUS::phase_t::command:
ProcessCommand(); ProcessCommand();
break; break;
@ -718,7 +661,7 @@ void ScsiController::Receive()
bool ScsiController::XferMsg(int msg) bool ScsiController::XferMsg(int msg)
{ {
assert(ctrl.phase == BUS::phase_t::msgout); assert(IsMsgOut());
// Save message out data // Save message out data
if (scsi.atnmsg) { if (scsi.atnmsg) {
@ -732,17 +675,14 @@ bool ScsiController::XferMsg(int msg)
void ScsiController::ReceiveBytes() void ScsiController::ReceiveBytes()
{ {
LOGTRACE("%s",__PRETTY_FUNCTION__)
// REQ is low
assert(!bus->GetREQ()); assert(!bus->GetREQ());
assert(!bus->GetIO()); assert(!bus->GetIO());
if (ctrl.length) { if (HasValidLength()) {
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length) LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
// If not able to receive all, move to status phase // 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) { len != ctrl.length) {
LOGERROR("%s Not able to receive %d bytes of data, only received %d", LOGERROR("%s Not able to receive %d bytes of data, only received %d",
__PRETTY_FUNCTION__, ctrl.length, len) __PRETTY_FUNCTION__, ctrl.length, len)
@ -752,8 +692,7 @@ void ScsiController::ReceiveBytes()
bytes_to_transfer = ctrl.length; bytes_to_transfer = ctrl.length;
ctrl.offset += ctrl.length; UpdateOffsetAndLength();
ctrl.length = 0;
return; return;
} }
@ -762,15 +701,14 @@ void ScsiController::ReceiveBytes()
bool result = true; bool result = true;
// Processing after receiving data (by phase) // Processing after receiving data (by phase)
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase)) LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase()))
switch (ctrl.phase) { switch (GetPhase()) {
case BUS::phase_t::dataout: case BUS::phase_t::dataout:
result = XferOut(false); result = XferOut(false);
break; break;
case BUS::phase_t::msgout: case BUS::phase_t::msgout:
ctrl.message = ctrl.buffer[0]; ctrl.message = GetBuffer()[0];
if (!XferMsg(ctrl.message)) { if (!XferMsg(ctrl.message)) {
// Immediately free the bus if message output fails // Immediately free the bus if message output fails
BusFree(); BusFree();
@ -792,7 +730,7 @@ void ScsiController::ReceiveBytes()
} }
// Move to next phase // Move to next phase
switch (ctrl.phase) { switch (GetPhase()) {
case BUS::phase_t::command: case BUS::phase_t::command:
ProcessCommand(); ProcessCommand();
break; break;
@ -813,7 +751,7 @@ void ScsiController::ReceiveBytes()
bool ScsiController::XferOut(bool cont) bool ScsiController::XferOut(bool cont)
{ {
assert(ctrl.phase == BUS::phase_t::dataout); assert(IsDataOut());
if (!is_byte_transfer) { if (!is_byte_transfer) {
return XferOutBlockOriented(cont); return XferOutBlockOriented(cont);
@ -823,17 +761,17 @@ bool ScsiController::XferOut(bool cont)
if (auto device = GetDeviceForLun(GetEffectiveLun()); if (auto device = GetDeviceForLun(GetEffectiveLun());
device != nullptr && GetOpcode() == scsi_command::eCmdWrite6) { 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; return false;
} }
void ScsiController::FlushUnit() void ScsiController::FlushUnit()
{ {
assert(ctrl.phase == BUS::phase_t::dataout); assert(IsDataOut());
auto disk = dynamic_cast<Disk *>(GetDeviceForLun(GetEffectiveLun())); auto disk = dynamic_cast<Disk *>(GetDeviceForLun(GetEffectiveLun()));
if (disk == nullptr) { if (disk == nullptr) {
@ -857,7 +795,7 @@ void ScsiController::FlushUnit()
// Without it we would not need this method at all. // 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? // ModeSelect is already handled in XferOutBlockOriented(). Why would it have to be handled once more?
try { try {
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset); disk->ModeSelect(ctrl.cmd, GetBuffer(), ctrl.offset);
} }
catch(const scsi_error_exception& e) { catch(const scsi_error_exception& e) {
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode()) LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
@ -882,9 +820,9 @@ void ScsiController::FlushUnit()
// *Reset offset and length // *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()) LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
@ -910,7 +848,7 @@ bool ScsiController::XferIn(BYTE *buf)
ctrl.next++; ctrl.next++;
// If things are normal, work setting // If things are normal, work setting
ctrl.offset = 0; ResetOffset();
break; break;
// Other (impossible) // Other (impossible)
@ -940,7 +878,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
case scsi_command::eCmdModeSelect6: case scsi_command::eCmdModeSelect6:
case scsi_command::eCmdModeSelect10: case scsi_command::eCmdModeSelect10:
try { try {
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset); disk->ModeSelect(ctrl.cmd, GetBuffer(), ctrl.offset);
} }
catch(const scsi_error_exception& e) { catch(const scsi_error_exception& e) {
Error(e.get_sense_key(), e.get_asc(), e.get_status()); 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 // Special case Write function for brige
// TODO This class must not know about SCSIBR // TODO This class must not know about SCSIBR
if (auto bridge = dynamic_cast<SCSIBR *>(disk); bridge) { 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 // Write failed
return false; return false;
} }
ctrl.offset = 0; ResetOffset();
break; break;
} }
// Special case Write function for DaynaPort // Special case Write function for DaynaPort
// TODO This class must not know about DaynaPort // TODO This class must not know about DaynaPort
if (auto daynaport = dynamic_cast<SCSIDaynaPort *>(disk); 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; ctrl.blocks = 0;
break; break;
} }
try { try {
disk->Write(ctrl.cmd, ctrl.buffer, ctrl.next - 1); disk->Write(ctrl.cmd, GetBuffer(), ctrl.next - 1);
} }
catch(const scsi_error_exception& e) { catch(const scsi_error_exception& e) {
Error(e.get_sense_key(), e.get_asc(), e.get_status()); Error(e.get_sense_key(), e.get_asc(), e.get_status());
@ -1002,7 +940,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
return false; return false;
} }
ctrl.offset = 0; ResetOffset();
break; break;
} }
@ -1020,93 +958,94 @@ bool ScsiController::XferOutBlockOriented(bool cont)
void ScsiController::ProcessCommand() 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++) { for (uint32_t i = 0; i < len; i++) {
ctrl.cmd[i] = ctrl.buffer[i]; ctrl.cmd[i] = GetBuffer()[i];
LOGTRACE("%s Command Byte %d: $%02X",__PRETTY_FUNCTION__, i, ctrl.cmd[i]) s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
} }
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
Execute(); 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() void ScsiController::ProcessMessage()
{ {
// Continue message out phase as long as ATN keeps asserting // Continue message out phase as long as ATN keeps asserting
if (bus->GetATN()) { if (bus->GetATN()) {
// Data transfer is 1 byte x 1 block // Data transfer is 1 byte x 1 block
ctrl.offset = 0; ResetOffset();
ctrl.length = 1; ctrl.length = 1;
ctrl.blocks = 1; ctrl.blocks = 1;
return; return;
} }
// Parsing messages sent by ATN
if (scsi.atnmsg) { if (scsi.atnmsg) {
int i = 0; ParseMessage();
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++;
}
} }
// Initialize ATN message reception status // Initialize ATN message reception status

View File

@ -10,8 +10,6 @@
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI device controller ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
@ -53,8 +51,11 @@ class ScsiController : public AbstractController
public: public:
// Maximum number of logical units
static const int LUN_MAX = 32;
ScsiController(shared_ptr<BUS>, int); ScsiController(shared_ptr<BUS>, int);
~ScsiController () override; ~ScsiController() override = default;
ScsiController(ScsiController&) = delete; ScsiController(ScsiController&) = delete;
ScsiController& operator=(const ScsiController&) = delete; ScsiController& operator=(const ScsiController&) = delete;
@ -64,8 +65,6 @@ public:
int GetEffectiveLun() const override; 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, 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; scsi_defs::status status = scsi_defs::status::CHECK_CONDITION) override;
@ -91,7 +90,6 @@ private:
uint32_t bytes_to_transfer = 0; uint32_t bytes_to_transfer = 0;
// Phases // Phases
void SetPhase(BUS::phase_t p) override { ctrl.phase = p; }
void BusFree() override; void BusFree() override;
void Selection() override; void Selection() override;
void Command() override; void Command() override;
@ -101,7 +99,7 @@ private:
// Data transfer // Data transfer
void Send(); void Send();
bool XferMsg(int); bool XferMsg(int);
bool XferIn(BYTE* buf); bool XferIn(vector<BYTE>&);
bool XferOut(bool); bool XferOut(bool);
bool XferOutBlockOriented(bool); bool XferOutBlockOriented(bool);
void ReceiveBytes(); void ReceiveBytes();
@ -111,6 +109,7 @@ private:
void Receive(); void Receive();
void ProcessCommand(); void ProcessCommand();
void ParseMessage();
void ProcessMessage(); void ProcessMessage();
void ScheduleShutdown(rascsi_shutdown_mode mode) override { shutdown_mode = mode; } void ScheduleShutdown(rascsi_shutdown_mode mode) override { shutdown_mode = mode; }

View File

@ -796,9 +796,6 @@ BYTE* CHostFilename::CopyName(BYTE* pWrite, const BYTE* pFirst, const BYTE* pLas
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostFilename::ConvertHuman(int nCount) void CHostFilename::ConvertHuman(int nCount)
{ {
char szHost[FILEPATH_MAX];
// Don't do conversion for special directory names // Don't do conversion for special directory names
if (m_szHost[0] == '.' && if (m_szHost[0] == '.' &&
(m_szHost[1] == '\0' || (m_szHost[1] == '.' && m_szHost[2] == '\0'))) { (m_szHost[1] == '\0' || (m_szHost[1] == '.' && m_szHost[2] == '\0'))) {
@ -844,6 +841,7 @@ void CHostFilename::ConvertHuman(int nCount)
BYTE* pExt = nullptr; BYTE* pExt = nullptr;
{ {
char szHost[FILEPATH_MAX];
strcpy(szHost, m_szHost); strcpy(szHost, m_szHost);
auto pRead = (const BYTE*)szHost; auto pRead = (const BYTE*)szHost;
BYTE* pWrite = szHuman; BYTE* pWrite = szHuman;
@ -1558,8 +1556,7 @@ void CHostPath::Refresh()
// If no match, confirm existence of real file // If no match, confirm existence of real file
strcpy(szPath, m_szHost); strcpy(szPath, m_szHost);
strcat(szPath, (const char*)pFilename->GetHuman()); strcat(szPath, (const char*)pFilename->GetHuman());
struct stat sb; if (struct stat sb; stat(S2U(szPath), &sb))
if (stat(S2U(szPath), &sb))
break; // Discover available patterns break; // Discover available patterns
} }
} }
@ -1575,7 +1572,7 @@ void CHostPath::Refresh()
strcpy(szPath, m_szHost); strcpy(szPath, m_szHost);
strcat(szPath, U2S(pe->d_name)); 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)) if (stat(S2U(szPath), &sb))
continue; continue;
@ -1654,8 +1651,7 @@ void CHostPath::Backup()
len--; len--;
assert(szPath[len] == '/'); assert(szPath[len] == '/');
szPath[len] = '\0'; szPath[len] = '\0';
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required if (struct stat sb; stat(S2U(szPath), &sb) == 0)
if (stat(S2U(szPath), &sb) == 0)
m_tBackup = sb.st_mtime; m_tBackup = sb.st_mtime;
} }
} }
@ -2291,8 +2287,7 @@ bool CHostFcb::Create(DWORD, bool bForce)
// Duplication check // Duplication check
if (!bForce) { if (!bForce) {
struct stat sb; //NOSONAR Cannot be declared in a separate statement because struct keyword is required if (struct stat sb; stat(S2U(m_szFilename), &sb) == 0)
if (stat(S2U(m_szFilename), &sb) == 0)
return false; return false;
} }
@ -2917,7 +2912,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
// Generate attribute // Generate attribute
if (DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY); if (DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
f.GetAttribute() != nAttribute) { 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)) if (stat(S2U(f.GetPath()), &sb))
return FS_FILENOTFND; return FS_FILENOTFND;
mode_t m = sb.st_mode & 0777; mode_t m = sb.st_mode & 0777;

View File

@ -62,7 +62,7 @@ CTapDriver::~CTapDriver()
LOGERROR("Can't open bridge socket: %s", strerror(errno)) LOGERROR("Can't open bridge socket: %s", strerror(errno))
} else { } else {
LOGDEBUG("brctl delif %s ras0", BRIDGE_NAME) 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("Warning: Removing ras0 from the bridge failed.")
LOGWARN("You may need to manually remove the ras0 tap device from the bridge") 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) LOGTRACE("Opened tap device %d", m_hTAP)
// IFF_NO_PI for no extra packet information // IFF_NO_PI for no extra packet information
ifreq ifr; ifreq ifr = {};
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
string dev = "ras0"; string dev = "ras0";
strncpy(ifr.ifr_name, dev.c_str(), IFNAMSIZ - 1); 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 // long long is required for compatibility with 32 bit platforms
auto mask = (long long)(pow(2, 32) - (1 << (32 - m))); auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
char buf[16]; netmask = to_string((mask >> 24) & 0xff) + '.' + to_string((mask >> 16) & 0xff) + '.' +
sprintf(buf, "%lld.%lld.%lld.%lld", (mask >> 24) & 0xff, (mask >> 16) & 0xff, (mask >> 8) & 0xff, to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff);
mask & 0xff);
netmask = buf;
} }
LOGTRACE("brctl addbr %s", BRIDGE_NAME) LOGTRACE("brctl addbr %s", BRIDGE_NAME)

View File

@ -34,15 +34,6 @@ DeviceFactory::DeviceFactory()
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 }; sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
sector_sizes[SCCD] = { 512, 2048}; 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; string network_interfaces;
for (const auto& network_interface : GetNetworkInterfaces()) { for (const auto& network_interface : GetNetworkInterfaces()) {
if (!network_interfaces.empty()) { if (!network_interfaces.empty()) {
@ -180,7 +171,7 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
break; break;
case SCMO: case SCMO:
device = make_unique<SCSIMO>(sector_sizes[SCMO], geometries[SCMO]); device = make_unique<SCSIMO>(sector_sizes[SCMO]);
device->SetProtectable(true); device->SetProtectable(true);
device->SetStoppable(true); device->SetStoppable(true);
device->SetRemovable(true); device->SetRemovable(true);
@ -232,17 +223,17 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
break; break;
} }
assert(device != nullptr); if (device != nullptr) {
PrimaryDevice *d = device.release();
PrimaryDevice *d = device.release();
if (d != nullptr) {
d->SetId(id); d->SetId(id);
devices.emplace(id, d); devices.emplace(id, d);
return d;
} }
return d; return nullptr;
} }
const unordered_set<uint32_t>& DeviceFactory::GetSectorSizes(PbDeviceType type) const const unordered_set<uint32_t>& DeviceFactory::GetSectorSizes(PbDeviceType type) const

View File

@ -21,8 +21,6 @@
using namespace std; //NOSONAR Not relevant for rascsi using namespace std; //NOSONAR Not relevant for rascsi
using namespace rascsi_interface; //NOSONAR Not relevant for rascsi using namespace rascsi_interface; //NOSONAR Not relevant for rascsi
using Geometry = pair<uint32_t, uint32_t>;
class PrimaryDevice; class PrimaryDevice;
class DeviceFactory class DeviceFactory
@ -50,9 +48,6 @@ private:
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes; 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<PbDeviceType, unordered_map<string, string>> default_params;
unordered_map<string, PbDeviceType> extension_mapping; unordered_map<string, PbDeviceType> extension_mapping;

View File

@ -60,20 +60,18 @@ Disk::Disk(const string& id) : ModePageDevice(id)
Disk::~Disk() Disk::~Disk()
{ {
// Save disk cache, only if ready // Save disk cache, only if ready
if (IsReady() && disk.dcache) { if (IsReady() && cache != nullptr) {
disk.dcache->Save(); cache->Save();
} }
delete disk.dcache;
} }
bool Disk::Dispatch(scsi_command cmd) bool Disk::Dispatch(scsi_command cmd)
{ {
// Media changes must be reported on the next access, i.e. not only for TEST UNIT READY // 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()); 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); 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) void Disk::Open(const Filepath& path)
{ {
assert(disk.blocks > 0); assert(blocks > 0);
SetReady(true); 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 // Can read/write open
if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) { if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) {
// Write permission // Write permission
@ -114,10 +108,16 @@ void Disk::Open(const Filepath& path)
SetLocked(false); 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() void Disk::FlushCache()
{ {
if (disk.dcache) { if (cache != nullptr) {
disk.dcache->Save(); cache->Save();
} }
} }
@ -146,8 +146,8 @@ void Disk::ReassignBlocks()
void Disk::Read(access_mode mode) void Disk::Read(access_mode mode)
{ {
if (uint64_t start; CheckAndGetStartAndCount(start, ctrl->blocks, mode)) { if (uint64_t start; CheckAndGetStartAndCount(start, ctrl->blocks, mode)) {
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start); ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length) LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, controller->GetLength())
// Set next block // Set next block
ctrl->next = start + 1; ctrl->next = start + 1;
@ -177,7 +177,7 @@ void Disk::Read16()
void Disk::ReadWriteLong10() void Disk::ReadWriteLong10()
{ {
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard // 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); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
@ -189,7 +189,7 @@ void Disk::ReadWriteLong10()
void Disk::ReadWriteLong16() void Disk::ReadWriteLong16()
{ {
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard // 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); 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 // Test reading
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start); ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
// Set next block // Set next block
ctrl->next = start + 1; ctrl->next = start + 1;
@ -331,24 +331,22 @@ void Disk::SynchronizeCache()
void Disk::ReadDefectData10() void Disk::ReadDefectData10()
{ {
int allocation_length = GetInt16(ctrl->cmd, 7); size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
if (allocation_length > 4) {
allocation_length = 4;
}
// The defect list is empty // The defect list is empty
memset(ctrl->buffer, 0, allocation_length); fill_n(controller->GetBuffer().begin(), allocation_length, 0);
ctrl->length = allocation_length; ctrl->length = (int)allocation_length;
EnterDataInPhase(); EnterDataInPhase();
} }
void Disk::MediumChanged() void Disk::MediumChanged()
{ {
assert(IsRemovable());
if (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); bool status = super::Eject(force);
if (status) { if (status) {
FlushCache(); FlushCache();
delete disk.dcache; cache.reset();
disk.dcache = nullptr;
// The image file for this drive is not in use anymore // 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) { if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) {
file_support->UnreserveFile(); file_support->UnreserveFile();
} }
@ -370,14 +366,11 @@ bool Disk::Eject(bool force)
return status; 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 // Get length, clear buffer
auto length = cdb[4]; auto length = (int)min((size_t)max_length, (size_t)cdb[4]);
if (length > max_length) { fill_n(buf.begin(), length, 0);
length = max_length;
}
memset(buf, 0, length);
// DEVICE SPECIFIC PARAMETER // DEVICE SPECIFIC PARAMETER
if (IsProtected()) { if (IsProtected()) {
@ -385,7 +378,7 @@ int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
} }
// Basic information // Basic information
int size = 4; int info_size = 4;
// Add block descriptor if DBD is 0 // Add block descriptor if DBD is 0
if ((cdb[1] & 0x08) == 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 // Only if ready
if (IsReady()) { if (IsReady()) {
// Short LBA mode parameter block descriptor (number of blocks and block length) // Short LBA mode parameter block descriptor (number of blocks and block length)
SetInt32(&buf[4], (uint32_t)GetBlockCount()); SetInt32(buf, 4, (uint32_t)GetBlockCount());
SetInt32(&buf[8], GetSectorSizeInBytes()); SetInt32(buf, 8, GetSectorSizeInBytes());
} }
size = 12; info_size = 12;
} }
size += super::AddModePages(cdb, &buf[size], length - size); info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
if (size > 255) { if (info_size > 255) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
// Do not return more than ALLOCATION LENGTH bytes // Do not return more than ALLOCATION LENGTH bytes
if (size > length) { if (info_size > length) {
size = length; info_size = length;
} }
// Final setting of mode data 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 // Get length, clear buffer
int length = GetInt16(cdb, 7); auto length = (int)min((size_t)max_length, (size_t)GetInt16(cdb, 7));
if (length > max_length) { fill_n(buf.begin(), length, 0);
length = max_length;
}
memset(buf, 0, length);
// DEVICE SPECIFIC PARAMETER // DEVICE SPECIFIC PARAMETER
if (IsProtected()) { if (IsProtected()) {
@ -433,7 +423,7 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
} }
// Basic Information // Basic Information
int size = 8; int info_size = 8;
// Add block descriptor if DBD is 0, only if ready // Add block descriptor if DBD is 0, only if ready
if ((cdb[1] & 0x08) == 0 && IsReady()) { 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; buf[7] = 0x08;
// Short LBA mode parameter block descriptor (number of blocks and block length) // Short LBA mode parameter block descriptor (number of blocks and block length)
SetInt32(&buf[8], (uint32_t)disk_blocks); SetInt32(buf, 8, (uint32_t)disk_blocks);
SetInt32(&buf[12], disk_size); SetInt32(buf, 12, disk_size);
size = 16; info_size = 16;
} }
else { else {
// Mode parameter header, LONGLBA // Mode parameter header, LONGLBA
@ -459,27 +449,27 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
buf[7] = 0x10; buf[7] = 0x10;
// Long LBA mode parameter block descriptor (number of blocks and block length) // Long LBA mode parameter block descriptor (number of blocks and block length)
SetInt64(&buf[8], disk_blocks); SetInt64(buf, 8, disk_blocks);
SetInt32(&buf[20], disk_size); SetInt32(buf, 20, disk_size);
size = 24; info_size = 24;
} }
} }
size += super::AddModePages(cdb, &buf[size], length - size); info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
if (size > 65535) { if (info_size > 65535) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
// Do not return more than ALLOCATION LENGTH bytes // Do not return more than ALLOCATION LENGTH bytes
if (size > length) { if (info_size > length) {
size = length; info_size = length;
} }
// Final setting of mode data 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 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); SetInt16(buf, 0x0a, 25);
// Set the number of bytes in the physical sector // Set the number of bytes in the physical sector
SetInt16(buf, 0x0c, 1 << disk.size); SetInt16(buf, 0x0c, 1 << size_shift_count);
// Interleave 1 // Interleave 1
SetInt16(buf, 0x0e, 1); SetInt16(buf, 0x0e, 1);
@ -570,7 +560,7 @@ void Disk::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
if (IsReady()) { if (IsReady()) {
// Set the number of cylinders (total number of blocks // Set the number of cylinders (total number of blocks
// divided by 25 sectors/track and 8 heads) // divided by 25 sectors/track and 8 heads)
uint64_t cylinders = disk.blocks; uint64_t cylinders = blocks;
cylinders >>= 3; cylinders >>= 3;
cylinders /= 25; cylinders /= 25;
SetInt32(buf, 0x01, (uint32_t)cylinders); 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 // 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__) LOGTRACE("%s", __PRETTY_FUNCTION__)
CheckReady(); CheckReady();
// Error if the total number of blocks is exceeded // 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); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
// leave it to the cache // 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); throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
} }
// Success // Success
return 1 << disk.size; return 1 << size_shift_count;
} }
int Disk::WriteCheck(uint64_t block) int Disk::WriteCheck(uint64_t block)
@ -641,7 +631,7 @@ int Disk::WriteCheck(uint64_t block)
CheckReady(); CheckReady();
// Error if the total number of blocks is exceeded // 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); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
@ -651,11 +641,11 @@ int Disk::WriteCheck(uint64_t block)
} }
// Success // 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 // 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__) 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 // 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); 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 // 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); throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
} }
} }
@ -709,23 +699,23 @@ void Disk::ReadCapacity10()
{ {
CheckReady(); CheckReady();
if (disk.blocks == 0) { if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT); 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) // Create end of logical block address (blocks-1)
uint64_t blocks = disk.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 the capacity exceeds 32 bit, -1 must be returned and the client has to use READ CAPACITY(16)
if (blocks > 4294967295) { if (capacity > 4294967295) {
blocks = -1; capacity = -1;
} }
SetInt32(&buf[0], (uint32_t)blocks); SetInt32(buf, 0, (uint32_t)capacity);
// Create block length (1 << disk.size) // Create block length (1 << size)
SetInt32(&buf[4], 1 << disk.size); SetInt32(buf, 4, 1 << size_shift_count);
// the size // the size
ctrl->length = 8; ctrl->length = 8;
@ -737,17 +727,17 @@ void Disk::ReadCapacity16()
{ {
CheckReady(); CheckReady();
if (disk.blocks == 0) { if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT); 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) // Create end of logical block address (blocks-1)
SetInt64(&buf[0], disk.blocks - 1); SetInt64(buf, 0, blocks - 1);
// Create block length (1 << disk.size) // Create block length (1 << size)
SetInt32(&buf[8], 1 << disk.size); SetInt32(buf, 8, 1 << size_shift_count);
buf[12] = 0; 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 bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mode mode) const
{ {
if (mode == RW6 || mode == SEEK6) { if (mode == RW6 || mode == SEEK6) {
start = ctrl->cmd[1] & 0x1f; start = GetInt24(ctrl->cmd, 1);
start <<= 8;
start |= ctrl->cmd[2];
start <<= 8;
start |= ctrl->cmd[3];
count = ctrl->cmd[4]; count = ctrl->cmd[4];
if (!count) { if (!count) {
@ -864,7 +850,7 @@ bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mod
uint32_t Disk::GetSectorSizeInBytes() const 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) void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
@ -877,19 +863,19 @@ void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
switch (size_in_bytes) { switch (size_in_bytes) {
case 512: case 512:
disk.size = 9; size_shift_count = 9;
break; break;
case 1024: case 1024:
disk.size = 10; size_shift_count = 10;
break; break;
case 2048: case 2048:
disk.size = 11; size_shift_count = 11;
break; break;
case 4096: case 4096:
disk.size = 12; size_shift_count = 12;
break; break;
default: 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 uint32_t Disk::GetConfiguredSectorSize() const
{ {
return configured_sector_size; 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()); if (unordered_set<uint32_t> sizes = device_factory.GetSectorSizes(GetType());
sizes.find(size) == sizes.end()) { sizes.find(configured_size) == sizes.end()) {
return false; return false;
} }
configured_sector_size = size; configured_sector_size = configured_size;
return true; return true;
} }
uint64_t Disk::GetBlockCount() const
{
return disk.blocks;
}
void Disk::SetBlockCount(uint64_t blocks)
{
disk.blocks = blocks;
}

View File

@ -29,19 +29,19 @@ class Disk : public ModePageDevice, public ScsiBlockCommands
{ {
enum access_mode { RW6, RW10, RW16, SEEK6, SEEK10 }; 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; unordered_set<uint32_t> sector_sizes;
uint32_t configured_sector_size = 0; uint32_t configured_sector_size = 0;
using disk_t = struct { // Sector size shift count (9=512, 10=1024, 11=2048, 12=4096)
uint32_t size; // Sector Size (9=512, 10=1024, 11=2048, 12=4096) uint32_t size_shift_count = 0;
uint64_t blocks; // Total number of sectors
DiskCache *dcache; // Disk cache
off_t image_offset; // Offset to actual data
bool is_medium_changed;
};
Dispatcher<Disk> dispatcher; // Total number of sectors
uint64_t blocks = 0;
bool is_medium_changed = false;
public: public:
@ -57,14 +57,14 @@ public:
// Command helpers // Command helpers
virtual int WriteCheck(uint64_t); 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; uint32_t GetSectorSizeInBytes() const;
bool IsSectorSizeConfigurable() const; bool IsSectorSizeConfigurable() const { return !sector_sizes.empty(); }
bool SetConfiguredSectorSize(const DeviceFactory&, uint32_t); bool SetConfiguredSectorSize(const DeviceFactory&, uint32_t);
uint64_t GetBlockCount() const; uint64_t GetBlockCount() const { return blocks; }
void FlushCache() override; void FlushCache() override;
private: private:
@ -105,12 +105,13 @@ private:
void ValidateBlockAddress(access_mode) const; void ValidateBlockAddress(access_mode) const;
bool CheckAndGetStartAndCount(uint64_t&, uint32_t&, access_mode) const; bool CheckAndGetStartAndCount(uint64_t&, uint32_t&, access_mode) const;
int ModeSense6(const vector<int>&, BYTE *, int) const override; int ModeSense6(const vector<int>&, vector<BYTE>&, int) const override;
int ModeSense10(const vector<int>&, BYTE *, int) const override; int ModeSense10(const vector<int>&, vector<BYTE>&, int) const override;
protected: protected:
virtual void Open(const Filepath&); virtual void Open(const Filepath&);
void SetUpCache(const Filepath&, off_t = 0);
void SetUpModePages(map<int, vector<byte>>&, int, bool) const override; void SetUpModePages(map<int, vector<byte>>&, int, bool) const override;
virtual void AddErrorPage(map<int, vector<byte>>&, bool) const; virtual void AddErrorPage(map<int, vector<byte>>&, bool) const;
@ -119,13 +120,12 @@ protected:
void AddCachePage(map<int, vector<byte>>&, bool) const; void AddCachePage(map<int, vector<byte>>&, bool) const;
virtual void AddVendorPage(map<int, vector<byte>>&, int, bool) const; virtual void AddVendorPage(map<int, vector<byte>>&, int, bool) const;
unordered_set<uint32_t> GetSectorSizes() 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); void SetSectorSizeInBytes(uint32_t);
uint32_t GetSectorSizeShiftCount() const; uint32_t GetSectorSizeShiftCount() const { return size_shift_count; }
void SetSectorSizeShiftCount(uint32_t); void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; }
uint32_t GetConfiguredSectorSize() const; uint32_t GetConfiguredSectorSize() const;
void SetBlockCount(uint64_t); void SetBlockCount(uint64_t b) { blocks = b; }
// Internal disk data unique_ptr<DiskCache> cache;
disk_t disk = {};
}; };

View File

@ -14,7 +14,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "log.h"
#include "disk_track.h" #include "disk_track.h"
#include "disk_cache.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; sec_path = path;
} }
DiskCache::~DiskCache()
{
// Clear the track
Clear();
}
void DiskCache::SetRawMode(bool raw)
{
// Configuration
cd_raw = raw;
}
bool DiskCache::Save() const bool DiskCache::Save() const
{ {
// Save track // Save track
@ -52,50 +39,21 @@ bool DiskCache::Save() const
return true; return true;
} }
//--------------------------------------------------------------------------- shared_ptr<DiskTrack> DiskCache::GetTrack(uint32_t block)
//
// Get disk cache information
//
//---------------------------------------------------------------------------
bool DiskCache::GetCache(int index, int& track, uint32_t& aserial) const
{ {
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 // Update first
UpdateSerialNumber(); UpdateSerialNumber();
// Calculate track (fixed to 256 sectors/track) // Calculate track (fixed to 256 sectors/track)
int track = block >> 8; int track = block >> 8;
// Get the track data // Get track data
const DiskTrack *disktrk = Assign(track); return Assign(track);
}
bool DiskCache::ReadSector(vector<BYTE>& buf, uint32_t block)
{
shared_ptr<DiskTrack> disktrk = GetTrack(block);
if (disktrk == nullptr) { if (disktrk == nullptr) {
return false; return false;
} }
@ -104,18 +62,9 @@ bool DiskCache::ReadSector(BYTE *buf, uint32_t block)
return disktrk->ReadSector(buf, block & 0xff); 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); shared_ptr<DiskTrack> disktrk = GetTrack(block);
// Update first
UpdateSerialNumber();
// Calculate track (fixed to 256 sectors/track)
int track = block >> 8;
// Get that track data
DiskTrack *disktrk = Assign(track);
if (disktrk == nullptr) { if (disktrk == nullptr) {
return false; return false;
} }
@ -129,7 +78,7 @@ bool DiskCache::WriteSector(const BYTE *buf, uint32_t block)
// Track Assignment // Track Assignment
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
DiskTrack* DiskCache::Assign(int track) shared_ptr<DiskTrack> DiskCache::Assign(int track)
{ {
assert(sec_size != 0); assert(sec_size != 0);
assert(track >= 0); assert(track >= 0);
@ -144,10 +93,10 @@ DiskTrack* DiskCache::Assign(int track)
} }
// Next, check for empty // Next, check for empty
for (int i = 0; i < CACHE_MAX; i++) { for (size_t i = 0; i < cache.size(); i++) {
if (!cache[i].disktrk) { if (cache[i].disktrk == nullptr) {
// Try loading // Try loading
if (Load(i, track)) { if (Load((int)i, track, nullptr)) {
// Success loading // Success loading
cache[i].serial = serial; cache[i].serial = serial;
return cache[i].disktrk; return cache[i].disktrk;
@ -162,10 +111,10 @@ DiskTrack* DiskCache::Assign(int track)
// Set index 0 as candidate c // Set index 0 as candidate c
uint32_t s = cache[0].serial; uint32_t s = cache[0].serial;
int c = 0; size_t c = 0;
// Compare candidate with serial and update to smaller one // 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); assert(cache[i].disktrk);
// Compare and update the existing serial // Compare and update the existing serial
@ -181,10 +130,10 @@ DiskTrack* DiskCache::Assign(int track)
} }
// Delete this track // Delete this track
DiskTrack *disktrk = cache[c].disktrk; shared_ptr<DiskTrack> disktrk = cache[c].disktrk;
cache[c].disktrk = nullptr; cache[c].disktrk.reset();
if (Load(c, track, disktrk)) { if (Load((int)c, track, disktrk)) {
// Successful loading // Successful loading
cache[c].serial = serial; cache[c].serial = serial;
return cache[c].disktrk; return cache[c].disktrk;
@ -199,11 +148,11 @@ DiskTrack* DiskCache::Assign(int track)
// Load cache // 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(track >= 0);
assert(!cache[index].disktrk); assert(cache[index].disktrk == nullptr);
// Get the number of sectors on this track // Get the number of sectors on this track
int sectors = sec_blocks - (track << 8); int sectors = sec_blocks - (track << 8);
@ -214,7 +163,7 @@ bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
// Create a disk track // Create a disk track
if (disktrk == nullptr) { if (disktrk == nullptr) {
disktrk = new DiskTrack(); disktrk = make_shared<DiskTrack>();
} }
// Initialize disk track // Initialize disk track
@ -223,7 +172,6 @@ bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
// Try loading // Try loading
if (!disktrk->Load(sec_path)) { if (!disktrk->Load(sec_path)) {
// Failure // Failure
delete disktrk;
return false; return false;
} }

View File

@ -16,43 +16,46 @@
#pragma once #pragma once
#include "filepath.h" #include "filepath.h"
#include <array>
#include <memory>
// Number of tracks to cache using namespace std; //NOSONAR Not relevant for rascsi
static const int CACHE_MAX = 16;
class DiskCache class DiskCache
{ {
// Number of tracks to cache
static const int CACHE_MAX = 16;
public: public:
// Internal data definition // Internal data definition
using cache_t = struct { using cache_t = struct {
DiskTrack *disktrk; // Disk Track shared_ptr<DiskTrack> disktrk; // Disk Track
uint32_t serial; // Serial uint32_t serial; // Serial
}; };
DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0);
~DiskCache(); ~DiskCache() = default;
DiskCache(DiskCache&) = delete; DiskCache(DiskCache&) = delete;
DiskCache& operator=(const 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 // Access
bool Save() const; // Save and release all bool Save() const; // Save and release all
bool ReadSector(BYTE *buf, uint32_t block); // Sector Read bool ReadSector(vector<BYTE>&, uint32_t); // Sector Read
bool WriteSector(const BYTE *buf, uint32_t block); // Sector Write bool WriteSector(const vector<BYTE>&, uint32_t); // Sector Write
bool GetCache(int index, int& track, uint32_t& serial) const; // Get cache information
private: private:
// Internal Management // Internal Management
void Clear(); // Clear all tracks shared_ptr<DiskTrack> Assign(int);
DiskTrack* Assign(int track); // Load track shared_ptr<DiskTrack> GetTrack(uint32_t);
bool Load(int index, int track, DiskTrack *disktrk = nullptr); // Load track bool Load(int index, int track, shared_ptr<DiskTrack>);
void UpdateSerialNumber(); // Update serial number void UpdateSerialNumber();
// Internal data // Internal data
cache_t cache[CACHE_MAX] = {}; // Cache management array<cache_t, CACHE_MAX> cache = {}; // Cache management
uint32_t serial = 0; // Last serial number uint32_t serial = 0; // Last serial number
Filepath sec_path; // Path Filepath sec_path; // Path
int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)

View File

@ -24,9 +24,6 @@ DiskTrack::~DiskTrack()
if (dt.buffer) { if (dt.buffer) {
free(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) 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 // Not needed if already loaded
if (dt.init) { if (dt.init) {
assert(dt.buffer); assert(dt.buffer);
assert(dt.changemap);
return true; return true;
} }
@ -86,7 +82,7 @@ bool DiskTrack::Load(const Filepath& path)
dt.length = length; dt.length = length;
} }
if (!dt.buffer) { if (dt.buffer == nullptr) {
return false; return false;
} }
@ -99,31 +95,16 @@ bool DiskTrack::Load(const Filepath& path)
dt.length = length; dt.length = length;
} }
// Reserve change map memory // Resize and clear changemap
if (dt.changemap == nullptr) { dt.changemap.resize(dt.sectors);
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool)); fill(dt.changemap.begin(), dt.changemap.end(), false);
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));
// Read from File // Read from File
Fileio fio; Fileio fio;
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) { if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
return false; return false;
} }
if (dt.raw) { if (dt.raw) {
// Split Reading // Split Reading
for (int i = 0; i < dt.sectors; i++) { for (int i = 0; i < dt.sectors; i++) {
@ -175,7 +156,6 @@ bool DiskTrack::Save(const Filepath& path)
// Need to write // Need to write
assert(dt.buffer); assert(dt.buffer);
assert(dt.changemap);
assert((dt.sectors > 0) && (dt.sectors <= 0x100)); assert((dt.sectors > 0) && (dt.sectors <= 0x100));
// Writing in RAW mode is not allowed // Writing in RAW mode is not allowed
@ -237,18 +217,18 @@ bool DiskTrack::Save(const Filepath& path)
} }
} }
// Close
fio.Close(); fio.Close();
// Drop the change flag and exit // 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; dt.changed = false;
return true; 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) LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
@ -265,13 +245,13 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
// Copy // Copy
assert(dt.buffer); assert(dt.buffer);
assert((dt.sectors > 0) && (dt.sectors <= 0x100)); 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 // Success
return true; 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((sec >= 0) && (sec < 0x100));
assert(!dt.raw); assert(!dt.raw);
@ -293,13 +273,13 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
// Compare // Compare
assert(dt.buffer); assert(dt.buffer);
assert((dt.sectors > 0) && (dt.sectors <= 0x100)); 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 // Exit normally since it's attempting to write the same thing
return true; return true;
} }
// Copy, change // Copy, change
memcpy(&dt.buffer[offset], buf, length); memcpy(&dt.buffer[offset], buf.data(), length);
dt.changemap[sec] = true; dt.changemap[sec] = true;
dt.changed = true; dt.changed = true;

View File

@ -16,6 +16,9 @@
#pragma once #pragma once
#include "filepath.h" #include "filepath.h"
#include <vector>
using namespace std; //NOSONAR Not relevant for rascsi
class DiskTrack class DiskTrack
{ {
@ -27,8 +30,7 @@ class DiskTrack
BYTE *buffer; // Data buffer BYTE *buffer; // Data buffer
bool init; // Is it initilized? bool init; // Is it initilized?
bool changed; // Changed flag bool changed; // Changed flag
DWORD maplen; // Changed map length std::vector<bool> changemap; // Changed map
bool *changemap; // Changed map
bool raw; // RAW mode flag bool raw; // RAW mode flag
off_t imgoffset; // Offset to actual data off_t imgoffset; // Offset to actual data
} dt = {}; } dt = {};
@ -49,8 +51,8 @@ private:
bool Save(const Filepath& path); bool Save(const Filepath& path);
// Read / Write // Read / Write
bool ReadSector(BYTE *buf, int sec) const; // Sector Read bool ReadSector(vector<BYTE>&, int) const; // Sector Read
bool WriteSector(const BYTE *buf, int sec); // Sector Write bool WriteSector(const vector<BYTE>& buf, int); // Sector Write
int GetTrack() const { return dt.track; } // Get track int GetTrack() const { return dt.track; } // Get track
}; };

View File

@ -25,6 +25,7 @@
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "host_services.h" #include "host_services.h"
#include <algorithm>
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; 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); 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 // Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) { if (!(cdb[1] & 0x08)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
int length = cdb[4]; auto length = (int)min((size_t)max_length, (size_t)cdb[4]);
if (length > max_length) { fill_n(buf.begin(), length, 0);
length = max_length;
}
memset(buf, 0, length);
// Basic Information // Basic Information
int size = 4; int size = 4;
size += super::AddModePages(cdb, &buf[size], length - size); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 255) { if (size > 255) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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; 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 // Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) { if (!(cdb[1] & 0x08)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
int length = (cdb[7] << 8) | cdb[8]; auto length = (int)min((size_t)max_length, (size_t)GetInt16(cdb, 7));
if (length > max_length) { fill_n(buf.begin(), length, 0);
length = max_length;
}
memset(buf, 0, length);
// Basic Information // Basic Information
int size = 8; int size = 8;
size += super::AddModePages(cdb, &buf[size], length - size); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 65535) { if (size > 65535) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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; size = length;
} }
SetInt16(buf, size); SetInt16(buf, 0, size);
return 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 void HostServices::AddRealtimeClockPage(map<int, vector<byte>>& pages, bool changeable) const
{ {
if (!changeable) { if (!changeable) {
std::time_t t = std::time(nullptr); time_t t = time(nullptr);
tm localtime; tm localtime;
localtime_r(&t, &localtime); localtime_r(&t, &localtime);

View File

@ -58,8 +58,8 @@ private:
Dispatcher<HostServices> dispatcher; Dispatcher<HostServices> dispatcher;
int ModeSense6(const vector<int>&, BYTE *, int) const override; int ModeSense6(const vector<int>&, vector<BYTE>&, int) const override;
int ModeSense10(const vector<int>&, BYTE *, int) const override; int ModeSense10(const vector<int>&, vector<BYTE>&, int) const override;
void AddRealtimeClockPage(map<int, vector<byte>>&, bool) const; void AddRealtimeClockPage(map<int, vector<byte>>&, bool) const;

View File

@ -11,12 +11,14 @@
#include "log.h" #include "log.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "mode_page_device.h" #include "mode_page_device.h"
#include <cstddef> #include <cstddef>
using namespace std; using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util;
ModePageDevice::ModePageDevice(const string& id) : PrimaryDevice(id) 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); 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) { if (max_length < 0) {
return 0; return 0;
@ -77,36 +79,34 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_leng
// Page 0 must be last // Page 0 must be last
if (!page0.empty()) { if (!page0.empty()) {
size_t offset = result.size();
// Page data // Page data
result.insert(result.end(), page0.begin(), page0.end()); result.insert(result.end(), page0.begin(), page0.end());
// Page payload size // 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 // Do not return more than the requested number of bytes
size_t size = (size_t)max_length < result.size() ? max_length : result.size(); size_t size = min((size_t)max_length, result.size());
memcpy(buf, result.data(), size); memcpy(&buf.data()[offset], result.data(), size);
return (int)size; return (int)size;
} }
void ModePageDevice::ModeSense6() void ModePageDevice::ModeSense6()
{ {
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer, ctrl->bufsize); ctrl->length = ModeSense6(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
EnterDataInPhase(); EnterDataInPhase();
} }
void ModePageDevice::ModeSense10() void ModePageDevice::ModeSense10()
{ {
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer, ctrl->bufsize); ctrl->length = ModeSense10(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
EnterDataInPhase(); 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); 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 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 // 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)) { if (GetType() != "SCHD" && GetType() != "SCRM" && GetType() != "SCMO" && (ctrl->cmd[1] & 0x01)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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 int ModePageDevice::ModeSelectCheck10() const
{ {
// Receive the data specified by the parameter length // Receive the data specified by the parameter length
int length = ctrl->cmd[7]; size_t length = min(controller->GetBufferSize(), (size_t)GetInt16(ctrl->cmd, 7));
length <<= 8;
length |= ctrl->cmd[8];
if (length > ctrl->bufsize) {
length = ctrl->bufsize;
}
return ModeSelectCheck(length); return ModeSelectCheck((int)length);
} }

View File

@ -25,11 +25,11 @@ public:
bool Dispatch(scsi_command) override; 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: 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; virtual void SetUpModePages(map<int, vector<byte>>&, int, bool) const = 0;
private: private:
@ -38,8 +38,8 @@ private:
Dispatcher<ModePageDevice> dispatcher; Dispatcher<ModePageDevice> dispatcher;
virtual int ModeSense6(const vector<int>&, BYTE *, int) const = 0; virtual int ModeSense6(const vector<int>&, vector<BYTE>&, int) const = 0;
virtual int ModeSense10(const vector<int>&, BYTE *, int) const = 0; virtual int ModeSense10(const vector<int>&, vector<BYTE>&, int) const = 0;
void ModeSense6(); void ModeSense6();
void ModeSense10(); void ModeSense10();

View File

@ -9,11 +9,13 @@
#include "log.h" #include "log.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "primary_device.h" #include "primary_device.h"
using namespace std; using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util;
PrimaryDevice::PrimaryDevice(const string& id) : Device(id) PrimaryDevice::PrimaryDevice(const string& id) : Device(id)
{ {
@ -53,12 +55,9 @@ void PrimaryDevice::Inquiry()
vector<byte> buf = InquiryInternal(); vector<byte> buf = InquiryInternal();
size_t allocation_length = ctrl->cmd[4] + (ctrl->cmd[3] << 8); size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
if (allocation_length > buf.size()) {
allocation_length = buf.size();
}
memcpy(ctrl->buffer, buf.data(), allocation_length); memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
ctrl->length = (uint32_t)allocation_length; ctrl->length = (uint32_t)allocation_length;
// Report if the device does not support the requested LUN // 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()) LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, GetId())
// Signal that the requested LUN does not exist // Signal that the requested LUN does not exist
ctrl->buffer[0] |= 0x7f; controller->GetBuffer()[0] |= 0x7f;
} }
EnterDataInPhase(); EnterDataInPhase();
@ -74,18 +73,17 @@ void PrimaryDevice::Inquiry()
void PrimaryDevice::ReportLuns() 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 // Only SELECT REPORT mode 0 is supported
if (ctrl->cmd[2]) { if (ctrl->cmd[2]) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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++) { for (int lun = 0; lun < controller->GetMaxLuns(); lun++) {
if (controller->HasDeviceForLun(lun)) { if (controller->HasDeviceForLun(lun)) {
size += 8; size += 8;
@ -93,12 +91,11 @@ void PrimaryDevice::ReportLuns()
} }
} }
buf[2] = (BYTE)(size >> 8); SetInt16(buf, 2, size);
buf[3] = (BYTE)size;
size += 8; size += 8;
ctrl->length = allocation_length < size ? allocation_length : size; ctrl->length = min(allocation_length, size);
EnterDataInPhase(); EnterDataInPhase();
} }
@ -118,17 +115,14 @@ void PrimaryDevice::RequestSense()
// Do not raise an exception here because the rest of the code must be executed // Do not raise an exception here because the rest of the code must be executed
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN); controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
ctrl->status = 0x00; controller->SetStatus(0);
} }
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense(); vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
size_t allocation_length = ctrl->cmd[4]; size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
if (allocation_length > buf.size()) {
allocation_length = buf.size();
}
memcpy(ctrl->buffer, buf.data(), allocation_length); memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
ctrl->length = (uint32_t)allocation_length; ctrl->length = (uint32_t)allocation_length;
EnterDataInPhase(); EnterDataInPhase();
@ -201,12 +195,13 @@ vector<byte> PrimaryDevice::HandleRequestSense() const
buf[12] = (byte)(GetStatusCode() >> 8); buf[12] = (byte)(GetStatusCode() >> 8);
buf[13] = (byte)GetStatusCode(); 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; 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__) LOGERROR("%s Writing bytes is not supported by this device", __PRETTY_FUNCTION__)

View File

@ -30,7 +30,7 @@ public:
virtual bool Dispatch(scsi_command); virtual bool Dispatch(scsi_command);
void SetController(AbstractController *); 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; } virtual int GetSendDelay() const { return BUS::SEND_NO_DELAY; }
protected: protected:

View File

@ -13,63 +13,61 @@
using namespace scsi_defs; 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); assert(length >= 0);
int offset = 0;
// PF // PF
if (cdb[1] & 0x10) { if (!(cdb[1] & 0x10)) {
bool has_valid_page_code = false; // 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 bool has_valid_page_code = false;
if (length >= 12) {
// Check the block length // Mode Parameter header
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) || int offset = 0;
buf[11] != (BYTE)sector_size) { if (length >= 12) {
// See below for details // 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") 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); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
} }
offset += 12; has_valid_page_code = true;
length -= 12; }
else {
LOGWARN("Unknown MODE SELECT page code: $%02X", page)
} }
// Parsing the page // Advance to the next page
// TODO The length handling is wrong in case of length < size int size = buf[offset + 1] + 2;
while (length > 0) { length -= size;
// Format device page offset += size;
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);
}
} }
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); 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]; 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) uint32_t scsi_command_util::GetInt32(const vector<int>& buf, int offset)
{ {
return ((uint32_t)buf[offset] << 24) | ((uint32_t)buf[offset + 1] << 16) | 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]; ((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) void scsi_command_util::SetInt16(vector<byte>& buf, int offset, int value)
{ {
buf[offset] = (byte)(value >> 8); buf[offset] = (byte)(value >> 8);
buf[offset + 1] = (byte)value; 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] = (byte)(value >> 24);
buf[offset + 1] = (byte)(value >> 16); buf[offset + 1] = (byte)(value >> 16);
buf[offset + 2] = (byte)(value >> 8); buf[offset + 2] = (byte)(value >> 8);
buf[offset + 3] = (byte)value; 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;
}

View File

@ -18,16 +18,17 @@ using namespace std; //NOSONAR Not relevant for rascsi
namespace scsi_command_util 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 EnrichFormatPage(map<int, vector<byte>>&, bool, int);
void AddAppleVendorModePage(map<int, vector<byte>>&, bool); void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
int GetInt16(const vector<int>&, int); int GetInt16(const vector<int>&, int);
int GetInt24(const vector<int>&, int);
uint32_t GetInt32(const vector<int>&, int); uint32_t GetInt32(const vector<int>&, int);
uint64_t GetInt64(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 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);
} }

View File

@ -79,20 +79,6 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
SetReady(true); SetReady(true);
SetReset(false); 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; return true;
} }
@ -144,10 +130,10 @@ vector<byte> SCSIDaynaPort::InquiryInternal() const
// - The SCSI/Link apparently has about 6KB buffer space for packets. // - 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; 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]; int requested_length = cdb[4];
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length) 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. // breaks because of this, the work-around has to be re-evaluated.
size = 64; size = 64;
} }
SetInt16(&buf[0], size); SetInt16(buf, 0, size);
SetInt32(&buf[2], m_tap.PendingPackets() ? 0x10 : 0x00); SetInt32(buf, 2, m_tap.PendingPackets() ? 0x10 : 0x00);
// Return the packet size + 2 for the length + 4 for the flag field // Return the packet size + 2 for the length + 4 for the flag field
// The CRC was already appended by the ctapdriver // The CRC was already appended by the ctapdriver
@ -291,19 +277,19 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
// XX XX ... is the actual packet // 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_format = cdb[5];
int data_length = cdb[4] + (cdb[3] << 8); int data_length = GetInt16(cdb, 3);
if (data_format == 0x00){ 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) LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
} }
else if (data_format == 0x80){ else if (data_format == 0x80){
// The data length is specified in the first 2 bytes of the payload // The data length is specified in the first 2 bytes of the payload
data_length=buf[1] + (buf[0] << 8); 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) LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
} }
else else
@ -331,33 +317,11 @@ bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t
// - long #3: frames lost // - 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); return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 4));
// 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;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -407,11 +371,7 @@ void SCSIDaynaPort::TestUnitReady()
void SCSIDaynaPort::Read6() void SCSIDaynaPort::Read6()
{ {
// Get record number and block number // Get record number and block number
uint32_t record = ctrl->cmd[1] & 0x1f; uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
record <<= 8;
record |= ctrl->cmd[2];
record <<= 8;
record |= ctrl->cmd[3];
ctrl->blocks=1; ctrl->blocks=1;
// If any commands have a bogus control value, they were probably not // 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) 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) LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
// Set next block // Set next block
@ -434,20 +394,16 @@ void SCSIDaynaPort::Read6()
void SCSIDaynaPort::Write6() void SCSIDaynaPort::Write6()
{ {
// Reallocate buffer (because it is not transfer for each block) // Ensure a sufficient buffer size (because it is not transfer for each block)
if (ctrl->bufsize < DAYNAPORT_BUFFER_SIZE) { controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
delete[] ctrl->buffer;
ctrl->buffer = new BYTE[ctrl->bufsize];
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
}
int data_format = ctrl->cmd[5]; int data_format = ctrl->cmd[5];
if(data_format == 0x00) { if (data_format == 0x00) {
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8); ctrl->length = GetInt16(ctrl->cmd, 3);
} }
else if (data_format == 0x80) { else if (data_format == 0x80) {
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8) + 8; ctrl->length = GetInt16(ctrl->cmd, 3 + 8);
} }
else { else {
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format) LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
@ -467,7 +423,7 @@ void SCSIDaynaPort::Write6()
void SCSIDaynaPort::RetrieveStatistics() void SCSIDaynaPort::RetrieveStatistics()
{ {
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer); ctrl->length = RetrieveStats(ctrl->cmd, controller->GetBuffer());
// Set next block // Set next block
ctrl->blocks = 1; 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" // 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]){ switch(ctrl->cmd[5]){
case CMD_SCSILINK_SETMODE: case CMD_SCSILINK_SETMODE:
// TODO Not implemented, do nothing // TODO Not implemented, do nothing

View File

@ -24,8 +24,9 @@
// This does NOT include the file system functionality that is present // This does NOT include the file system functionality that is present
// in the Sharp X68000 host bridge. // in the Sharp X68000 host bridge.
// //
// Note: This requires the DaynaPort SCSI Link driver. // Note: This requires a DaynaPort SCSI Link driver.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "os.h" #include "os.h"
@ -42,8 +43,8 @@
//=========================================================================== //===========================================================================
class SCSIDaynaPort final : public Disk class SCSIDaynaPort final : public Disk
{ {
public: public:
SCSIDaynaPort(); SCSIDaynaPort();
~SCSIDaynaPort() override = default; ~SCSIDaynaPort() override = default;
SCSIDaynaPort(SCSIDaynaPort&) = delete; SCSIDaynaPort(SCSIDaynaPort&) = delete;
@ -54,15 +55,13 @@ public:
// Commands // Commands
vector<byte> InquiryInternal() const override; vector<byte> InquiryInternal() const override;
int Read(const vector<int>&, BYTE *, uint64_t) override; int Read(const vector<int>&, vector<BYTE>&, uint64_t) override;
bool WriteBytes(const vector<int>&, const BYTE *, uint64_t); bool WriteBytes(const vector<int>&, const vector<BYTE>&, uint64_t);
int WriteCheck(uint64_t block) override; 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>&); bool EnableInterface(const vector<int>&);
void SetMacAddr(const vector<int>&, BYTE *); // Set MAC address
void TestUnitReady() override; void TestUnitReady() override;
void Read6() override; void Read6() override;
void Write6() override; void Write6() override;
@ -108,19 +107,19 @@ private:
uint32_t length; uint32_t length;
read_data_flags_t flags; read_data_flags_t flags;
byte pad; 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)) { 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 frame_alignment_errors;
uint32_t crc_errors; uint32_t crc_errors;
uint32_t frames_lost; uint32_t frames_lost;
}; };
scsi_resp_link_stats_t m_scsi_link_stats = { scsi_resp_link_stats_t m_scsi_link_stats = {
//MAC address of @PotatoFi's DayanPort // 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} }, .mac_address = { byte{0x00}, byte{0x80}, byte{0x19}, byte{0x10}, byte{0x98}, byte{0xe3} },
.frame_alignment_errors = 0, .frame_alignment_errors = 0,
.crc_errors = 0, .crc_errors = 0,
.frames_lost = 0, .frames_lost = 0,
@ -130,6 +129,4 @@ private:
// TAP valid flag // TAP valid flag
bool m_bTapEnable = false; bool m_bTapEnable = false;
array<byte, 6> m_mac_addr;
}; };

View File

@ -37,12 +37,6 @@ SCSIBR::SCSIBR() : Disk("SCBR")
dispatcher.Add(scsi_command::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10); 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) bool SCSIBR::Init(const unordered_map<string, string>& params)
{ {
SetParams(params); SetParams(params);
@ -54,17 +48,16 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
LOGERROR("Unable to open the TAP interface") LOGERROR("Unable to open the TAP interface")
return false; return false;
} }
#endif
// Generate MAC Address // Generate MAC Address
memset(mac_addr, 0x00, 6);
if (m_bTapEnable) { if (m_bTapEnable) {
tap.GetMacAddr(mac_addr); tap.GetMacAddr(mac_addr.data());
mac_addr[5]++; mac_addr[5]++;
} }
// Packet reception flag OFF // Packet reception flag OFF
packet_enable = false; packet_enable = false;
#endif
SetReady(m_bTapEnable); SetReady(m_bTapEnable);
@ -84,11 +77,10 @@ bool SCSIBR::Dispatch(scsi_command cmd)
vector<byte> SCSIBR::InquiryInternal() const 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 // The bridge returns more additional bytes than the other devices
auto buf = vector<byte>(0x1F + 8 + 5); buf.resize(0x1F + 8 + 5);
memcpy(buf.data(), b.data(), b.size());
buf[4] = byte{0x1F + 8}; buf[4] = byte{0x1F + 8};
@ -112,7 +104,7 @@ void SCSIBR::TestUnitReady()
EnterStatusPhase(); EnterStatusPhase();
} }
int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf) int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
{ {
// Type // Type
int type = cdb[2]; int type = cdb[2];
@ -138,18 +130,18 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
if (phase == 0) { if (phase == 0) {
// Get packet size // Get packet size
ReceivePacket(); ReceivePacket();
SetInt16(&buf[0], packet_len); SetInt16(buf, 0, packet_len);
return 2; return 2;
} else { } else {
// Get package data // Get package data
GetPacketBuf(buf); GetPacketBuf(buf, 0);
return packet_len; return packet_len;
} }
case 2: // Received packet acquisition (size + buffer simultaneously) case 2: // Received packet acquisition (size + buffer simultaneously)
ReceivePacket(); ReceivePacket();
SetInt16(&buf[0], packet_len); SetInt16(buf, 0, packet_len);
GetPacketBuf(&buf[2]); GetPacketBuf(buf, 2);
return packet_len + 2; return packet_len + 2;
case 3: { case 3: {
@ -159,14 +151,11 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
int total_len = 0; int total_len = 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
ReceivePacket(); ReceivePacket();
SetInt16(&buf[0], packet_len); SetInt16(buf, total_len, packet_len);
// TODO Callee should not modify buffer pointer
buf += 2;
total_len += 2; total_len += 2;
if (packet_len == 0) if (packet_len == 0)
break; break;
GetPacketBuf(buf); GetPacketBuf(buf, 0);
buf += packet_len;
total_len += packet_len; total_len += packet_len;
} }
return total_len; return total_len;
@ -203,7 +192,7 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
return 0; 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 // Type
int type = cdb[2]; int type = cdb[2];
@ -215,11 +204,7 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
int phase = cdb[9]; int phase = cdb[9];
// Get the number of lights // Get the number of lights
int len = cdb[6]; int len = GetInt24(cdb, 6);
len <<= 8;
len |= cdb[7];
len <<= 8;
len |= cdb[8];
switch (type) { switch (type) {
case 1: // Ethernet case 1: // Ethernet
@ -229,11 +214,11 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
} }
switch (func) { switch (func) {
case 0: // MAC address setting case 0:
SetMacAddr(buf); SetMacAddr(buf);
return true; return true;
case 1: // Send packet case 1:
SendPacket(buf, len); SendPacket(buf, len);
return true; return true;
@ -267,14 +252,10 @@ bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
void SCSIBR::GetMessage10() void SCSIBR::GetMessage10()
{ {
// Reallocate buffer (because it is not transfer for each block) // Ensure a sufficient buffer size (because it is not a transfer for each block)
if (ctrl->bufsize < 0x1000000) { controller->AllocateBuffer(0x1000000);
delete[] ctrl->buffer;
ctrl->bufsize = 0x1000000;
ctrl->buffer = new BYTE[ctrl->bufsize];
}
ctrl->length = GetMessage10(ctrl->cmd, ctrl->buffer); ctrl->length = GetMessage10(ctrl->cmd, controller->GetBuffer());
if (ctrl->length <= 0) { if (ctrl->length <= 0) {
throw scsi_error_exception(); throw scsi_error_exception();
} }
@ -295,24 +276,14 @@ void SCSIBR::GetMessage10()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::SendMessage10() void SCSIBR::SendMessage10()
{ {
// Reallocate buffer (because it is not transfer for each block) ctrl->length = GetInt24(ctrl->cmd, 6);
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];
if (ctrl->length <= 0) { if (ctrl->length <= 0) {
throw scsi_error_exception(); throw scsi_error_exception();
} }
// Ensure a sufficient buffer size (because it is not a transfer for each block)
controller->AllocateBuffer(0x1000000);
// Set next block // Set next block
ctrl->blocks = 1; ctrl->blocks = 1;
ctrl->next = 1; ctrl->next = 1;
@ -320,39 +291,36 @@ void SCSIBR::SendMessage10()
EnterDataOutPhase(); EnterDataOutPhase();
} }
int SCSIBR::GetMacAddr(BYTE *mac) const int SCSIBR::GetMacAddr(vector<BYTE>& mac) const
{ {
memcpy(mac, mac_addr, 6); memcpy(mac.data(), mac_addr.data(), mac_addr.size());
return 6; 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() void SCSIBR::ReceivePacket()
{ {
static const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
// previous packet has not been received // previous packet has not been received
if (packet_enable) { if (packet_enable) {
return; return;
} }
// Receive packet // Receive packet
packet_len = tap.Receive(packet_buf); packet_len = tap.Receive(packet_buf.data());
// Check if received packet // 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; packet_len = 0;
return;
} }
// Discard if it exceeds the buffer size // Discard if it exceeds the buffer size
if (packet_len > 2048) { if (packet_len > 2048) {
packet_len = 0; packet_len = 0;
return;
} }
// Store in receive buffer // 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 // Size limit
int len = packet_len; int len = packet_len;
@ -370,15 +338,15 @@ void SCSIBR::GetPacketBuf(BYTE *buf)
} }
// Copy // Copy
memcpy(buf, packet_buf, len); memcpy(buf.data() + index, packet_buf.data(), len);
// Received // Received
packet_enable = false; 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 // $40 - Device Boot
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_InitDevice(BYTE *buf) void SCSIBR::FS_InitDevice(vector<BYTE>& buf)
{ {
fs.Reset(); 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 // $41 - Directory Check
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_CheckDir(BYTE *buf) void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); fsresult = fs.CheckDir(nUnit, pNamests);
} }
@ -413,13 +381,13 @@ void SCSIBR::FS_CheckDir(BYTE *buf)
// $42 - Create Directory // $42 - Create Directory
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_MakeDir(BYTE *buf) void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); fsresult = fs.MakeDir(nUnit, pNamests);
} }
@ -429,13 +397,13 @@ void SCSIBR::FS_MakeDir(BYTE *buf)
// $43 - Remove Directory // $43 - Remove Directory
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_RemoveDir(BYTE *buf) void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); fsresult = fs.RemoveDir(nUnit, pNamests);
} }
@ -445,16 +413,16 @@ void SCSIBR::FS_RemoveDir(BYTE *buf)
// $44 - Rename // $44 - Rename
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Rename(BYTE *buf) void SCSIBR::FS_Rename(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); 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); fsresult = fs.Rename(nUnit, pNamests, pNamestsNew);
} }
@ -464,13 +432,13 @@ void SCSIBR::FS_Rename(BYTE *buf)
// $45 - Delete File // $45 - Delete File
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Delete(BYTE *buf) void SCSIBR::FS_Delete(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); fsresult = fs.Delete(nUnit, pNamests);
} }
@ -480,17 +448,17 @@ void SCSIBR::FS_Delete(BYTE *buf)
// $46 - Get / Set file attributes // $46 - Get / Set file attributes
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Attribute(BYTE *buf) void SCSIBR::FS_Attribute(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); i += sizeof(Human68k::namests_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nHumanAttribute = ntohl(*dp); uint32_t nHumanAttribute = ntohl(*dp);
fsresult = fs.Attribute(nUnit, pNamests, nHumanAttribute); fsresult = fs.Attribute(nUnit, pNamests, nHumanAttribute);
} }
@ -500,20 +468,20 @@ void SCSIBR::FS_Attribute(BYTE *buf)
// $47 - File Search // $47 - File Search
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Files(BYTE *buf) void SCSIBR::FS_Files(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); 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); 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->sector = ntohl(files->sector);
files->offset = ntohs(files->offset); files->offset = ntohs(files->offset);
@ -541,17 +509,17 @@ void SCSIBR::FS_Files(BYTE *buf)
// $48 - File next search // $48 - File next search
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_NFiles(BYTE *buf) void SCSIBR::FS_NFiles(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); 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->sector = ntohl(files->sector);
files->offset = ntohs(files->offset); files->offset = ntohs(files->offset);
@ -579,28 +547,28 @@ void SCSIBR::FS_NFiles(BYTE *buf)
// $49 - File Creation // $49 - File Creation
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Create(BYTE *buf) void SCSIBR::FS_Create(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); 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); 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); i += sizeof(Human68k::fcb_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nAttribute = ntohl(*dp); uint32_t nAttribute = ntohl(*dp);
i += sizeof(DWORD); i += sizeof(uint32_t);
auto bp = (int*)&buf[i]; auto bp = (int*)&(buf.data()[i]);
DWORD bForce = ntohl(*bp); uint32_t bForce = ntohl(*bp);
pFcb->fileptr = ntohl(pFcb->fileptr); pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -628,20 +596,20 @@ void SCSIBR::FS_Create(BYTE *buf)
// $4A - Open File // $4A - Open File
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Open(BYTE *buf) void SCSIBR::FS_Open(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); 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); 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->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -669,17 +637,17 @@ void SCSIBR::FS_Open(BYTE *buf)
// $4B - Close File // $4B - Close File
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Close(BYTE *buf) void SCSIBR::FS_Close(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); 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->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -707,17 +675,17 @@ void SCSIBR::FS_Close(BYTE *buf)
// $4C - Read File // $4C - Read File
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Read(BYTE *buf) void SCSIBR::FS_Read(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
int i = sizeof(DWORD); 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); i += sizeof(Human68k::fcb_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nSize = ntohl(*dp); uint32_t nSize = ntohl(*dp);
pFcb->fileptr = ntohl(pFcb->fileptr); pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -725,7 +693,7 @@ void SCSIBR::FS_Read(BYTE *buf)
pFcb->date = ntohs(pFcb->date); pFcb->date = ntohs(pFcb->date);
pFcb->size = ntohl(pFcb->size); 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->fileptr = htonl(pFcb->fileptr);
pFcb->mode = htons(pFcb->mode); pFcb->mode = htons(pFcb->mode);
@ -747,17 +715,17 @@ void SCSIBR::FS_Read(BYTE *buf)
// $4D - Write file // $4D - Write file
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Write(BYTE *buf) void SCSIBR::FS_Write(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
int i = sizeof(DWORD); 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); i += sizeof(Human68k::fcb_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nSize = ntohl(*dp); uint32_t nSize = ntohl(*dp);
pFcb->fileptr = ntohl(pFcb->fileptr); pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -765,7 +733,7 @@ void SCSIBR::FS_Write(BYTE *buf)
pFcb->date = ntohs(pFcb->date); pFcb->date = ntohs(pFcb->date);
pFcb->size = ntohl(pFcb->size); 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->fileptr = htonl(pFcb->fileptr);
pFcb->mode = htons(pFcb->mode); pFcb->mode = htons(pFcb->mode);
@ -785,20 +753,20 @@ void SCSIBR::FS_Write(BYTE *buf)
// $4E - Seek file // $4E - Seek file
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Seek(BYTE *buf) void SCSIBR::FS_Seek(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
int i = sizeof(DWORD); 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); i += sizeof(Human68k::fcb_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nMode = ntohl(*dp); uint32_t nMode = ntohl(*dp);
i += sizeof(DWORD); i += sizeof(uint32_t);
auto ip = (const int*)&buf[i]; auto ip = (const int*)&(buf.data()[i]);
int nOffset = ntohl(*ip); int nOffset = ntohl(*ip);
pFcb->fileptr = ntohl(pFcb->fileptr); pFcb->fileptr = ntohl(pFcb->fileptr);
@ -827,21 +795,21 @@ void SCSIBR::FS_Seek(BYTE *buf)
// $4F - File Timestamp Get / Set // $4F - File Timestamp Get / Set
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_TimeStamp(BYTE *buf) void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nKey = ntohl(*dp); uint32_t nKey = ntohl(*dp);
i += sizeof(DWORD); i += sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&buf[i]; auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
i += sizeof(Human68k::fcb_t); i += sizeof(Human68k::fcb_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nHumanTime = ntohl(*dp); uint32_t nHumanTime = ntohl(*dp);
pFcb->fileptr = ntohl(pFcb->fileptr); pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode); pFcb->mode = ntohs(pFcb->mode);
@ -869,10 +837,10 @@ void SCSIBR::FS_TimeStamp(BYTE *buf)
// $50 - Get Capacity // $50 - Get Capacity
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_GetCapacity(BYTE *buf) void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
Human68k::capacity_t cap; Human68k::capacity_t cap;
fsresult = fs.GetCapacity(nUnit, &cap); fsresult = fs.GetCapacity(nUnit, &cap);
@ -882,7 +850,7 @@ void SCSIBR::FS_GetCapacity(BYTE *buf)
cap.sectors = htons(cap.sectors); cap.sectors = htons(cap.sectors);
cap.bytes = htons(cap.bytes); 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); fsoutlen = sizeof(Human68k::capacity_t);
} }
@ -891,17 +859,17 @@ void SCSIBR::FS_GetCapacity(BYTE *buf)
// $51 - Drive status inspection/control // $51 - Drive status inspection/control
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_CtrlDrive(BYTE *buf) void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); 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); 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); fsoutlen = sizeof(Human68k::ctrldrive_t);
} }
@ -910,10 +878,10 @@ void SCSIBR::FS_CtrlDrive(BYTE *buf)
// $52 - Get DPB // $52 - Get DPB
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_GetDPB(BYTE *buf) void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
Human68k::dpb_t dpb; Human68k::dpb_t dpb;
fsresult = fs.GetDPB(nUnit, &dpb); fsresult = fs.GetDPB(nUnit, &dpb);
@ -925,7 +893,7 @@ void SCSIBR::FS_GetDPB(BYTE *buf)
dpb.cluster_max = htons(dpb.cluster_max); dpb.cluster_max = htons(dpb.cluster_max);
dpb.root_sector = htons(dpb.root_sector); 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); fsoutlen = sizeof(Human68k::dpb_t);
} }
@ -934,20 +902,20 @@ void SCSIBR::FS_GetDPB(BYTE *buf)
// $53 - Read Sector // $53 - Read Sector
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_DiskRead(BYTE *buf) void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nSector = ntohl(*dp); uint32_t nSector = ntohl(*dp);
i += sizeof(DWORD); i += sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nSize = ntohl(*dp); uint32_t nSize = ntohl(*dp);
fsresult = fs.DiskRead(nUnit, fsout, nSector, nSize); fsresult = fs.DiskRead(nUnit, fsout.data(), nSector, nSize);
fsoutlen = 0x200; fsoutlen = 0x200;
} }
@ -956,10 +924,10 @@ void SCSIBR::FS_DiskRead(BYTE *buf)
// $54 - Write Sector // $54 - Write Sector
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_DiskWrite(BYTE *buf) void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
fsresult = fs.DiskWrite(nUnit); fsresult = fs.DiskWrite(nUnit);
} }
@ -969,17 +937,17 @@ void SCSIBR::FS_DiskWrite(BYTE *buf)
// $55 - IOCTRL // $55 - IOCTRL
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Ioctrl(BYTE *buf) void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
int i = sizeof(DWORD); int i = sizeof(uint32_t);
dp = (DWORD*)&buf[i]; dp = (uint32_t*)&(buf.data()[i]);
DWORD nFunction = ntohl(*dp); uint32_t nFunction = ntohl(*dp);
i += sizeof(DWORD); i += sizeof(uint32_t);
auto pIoctrl = (Human68k::ioctrl_t*)&buf[i]; auto pIoctrl = (Human68k::ioctrl_t*)&(buf.data()[i]);
switch (nFunction) { switch (nFunction) {
case 2: case 2:
@ -1015,10 +983,10 @@ void SCSIBR::FS_Ioctrl(BYTE *buf)
// $56 - Flush // $56 - Flush
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Flush(BYTE *buf) void SCSIBR::FS_Flush(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
fsresult = fs.Flush(nUnit); fsresult = fs.Flush(nUnit);
} }
@ -1028,10 +996,10 @@ void SCSIBR::FS_Flush(BYTE *buf)
// $57 - Check Media // $57 - Check Media
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_CheckMedia(BYTE *buf) void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
fsresult = fs.CheckMedia(nUnit); fsresult = fs.CheckMedia(nUnit);
} }
@ -1041,10 +1009,10 @@ void SCSIBR::FS_CheckMedia(BYTE *buf)
// $58 - Lock // $58 - Lock
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::FS_Lock(BYTE *buf) void SCSIBR::FS_Lock(vector<BYTE>& buf)
{ {
auto dp = (DWORD*)buf; auto dp = (uint32_t*)buf.data();
DWORD nUnit = ntohl(*dp); uint32_t nUnit = ntohl(*dp);
fsresult = fs.Lock(nUnit); fsresult = fs.Lock(nUnit);
} }
@ -1054,11 +1022,11 @@ void SCSIBR::FS_Lock(BYTE *buf)
// Read Filesystem (result code) // 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); *dp = htonl(fsresult);
return sizeof(DWORD); return sizeof(uint32_t);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -1066,9 +1034,9 @@ int SCSIBR::ReadFsResult(BYTE *buf) const
// Read Filesystem (return data) // 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; return fsoutlen;
} }
@ -1077,9 +1045,9 @@ int SCSIBR::ReadFsOut(BYTE *buf) const
// Read file system (return option data) // 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; return fsoptlen;
} }
@ -1088,7 +1056,7 @@ int SCSIBR::ReadFsOpt(BYTE *buf) const
// Write Filesystem // Write Filesystem
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIBR::WriteFs(int func, BYTE *buf) void SCSIBR::WriteFs(int func, vector<BYTE>& buf)
{ {
fsresult = FS_FATAL_INVALIDCOMMAND; fsresult = FS_FATAL_INVALIDCOMMAND;
fsoutlen = 0; fsoutlen = 0;
@ -1096,32 +1064,83 @@ void SCSIBR::WriteFs(int func, BYTE *buf)
func &= 0x1f; func &= 0x1f;
switch (func) { switch (func) {
case 0x00: return FS_InitDevice(buf); // $40 - start device case 0x00:
case 0x01: return FS_CheckDir(buf); // $41 - directory check FS_InitDevice(buf); // $40 - start device
case 0x02: return FS_MakeDir(buf); // $42 - create directory break;
case 0x03: return FS_RemoveDir(buf); // $43 - remove directory case 0x01:
case 0x04: return FS_Rename(buf); // $44 - change file name FS_CheckDir(buf); // $41 - directory check
case 0x05: return FS_Delete(buf); // $45 - delete file break;
case 0x06: return FS_Attribute(buf); // $46 - Get/set file attribute case 0x02:
case 0x07: return FS_Files(buf); // $47 - file search FS_MakeDir(buf); // $42 - create directory
case 0x08: return FS_NFiles(buf); // $48 - next file search break;
case 0x09: return FS_Create(buf); // $49 - create file case 0x03:
case 0x0A: return FS_Open(buf); // $4A - File open FS_RemoveDir(buf); // $43 - remove directory
case 0x0B: return FS_Close(buf); // $4B - File close break;
case 0x0C: return FS_Read(buf); // $4C - read file case 0x04:
case 0x0D: return FS_Write(buf); // $4D - write file FS_Rename(buf); // $44 - change file name
case 0x0E: return FS_Seek(buf); // $4E - File seek break;
case 0x0F: return FS_TimeStamp(buf); // $4F - Get/set file modification time case 0x05:
case 0x10: return FS_GetCapacity(buf); // $50 - get capacity FS_Delete(buf); // $45 - delete file
case 0x11: return FS_CtrlDrive(buf); // $51 - Drive control/state check break;
case 0x12: return FS_GetDPB(buf); // $52 - Get DPB case 0x06:
case 0x13: return FS_DiskRead(buf); // $53 - read sector FS_Attribute(buf); // $46 - Get/set file attribute
case 0x14: return FS_DiskWrite(buf); // $54 - write sector break;
case 0x15: return FS_Ioctrl(buf); // $55 - IOCTRL case 0x07:
case 0x16: return FS_Flush(buf); // $56 - flush FS_Files(buf); // $47 - file search
case 0x17: return FS_CheckMedia(buf); // $57 - check media exchange break;
case 0x18: return FS_Lock(buf); // $58 - exclusive control case 0x08:
default: break; 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) // 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());
} }

View File

@ -22,13 +22,18 @@
#include "ctapdriver.h" #include "ctapdriver.h"
#include "cfilesystem.h" #include "cfilesystem.h"
#include <string> #include <string>
#include <array>
using namespace std; //NOSONAR Not relevant for rascsi
class SCSIBR final : public Disk class SCSIBR final : public Disk
{ {
static constexpr const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
public: public:
SCSIBR(); SCSIBR();
~SCSIBR() override; ~SCSIBR() override = default;
SCSIBR(SCSIBR&) = delete; SCSIBR(SCSIBR&) = delete;
SCSIBR& operator=(const SCSIBR&) = delete; SCSIBR& operator=(const SCSIBR&) = delete;
@ -37,8 +42,8 @@ public:
// Commands // Commands
vector<byte> InquiryInternal() const override; vector<byte> InquiryInternal() const override;
int GetMessage10(const vector<int>&, BYTE *); int GetMessage10(const vector<int>&, vector<BYTE>&);
bool WriteBytes(const vector<int>&, BYTE *, uint64_t); bool WriteBytes(const vector<int>&, vector<BYTE>&, uint64_t);
void TestUnitReady() override; void TestUnitReady() override;
void GetMessage10(); void GetMessage10();
void SendMessage10(); void SendMessage10();
@ -49,56 +54,56 @@ private:
Dispatcher<SCSIBR> dispatcher; Dispatcher<SCSIBR> dispatcher;
int GetMacAddr(BYTE *buf) const; // Get MAC address int GetMacAddr(vector<BYTE>&) const; // Get MAC address
void SetMacAddr(const BYTE *buf); // Set MAC address void SetMacAddr(const vector<BYTE>&); // Set MAC address
void ReceivePacket(); // Receive a packet void ReceivePacket(); // Receive a packet
void GetPacketBuf(BYTE *buf); // Get a packet void GetPacketBuf(vector<BYTE>&, int); // Get a packet
void SendPacket(const BYTE *buf, int len); // Send a packet void SendPacket(const vector<BYTE>&, int); // Send a packet
CTapDriver tap; // TAP driver CTapDriver tap; // TAP driver
bool m_bTapEnable = false; // TAP valid flag 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 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 bool packet_enable = false; // Received packet valid
int ReadFsResult(BYTE *buf) const; // Read filesystem (result code) int ReadFsResult(vector<BYTE>&) const; // Read filesystem (result code)
int ReadFsOut(BYTE *buf) const; // Read filesystem (return data) int ReadFsOut(vector<BYTE>&) const; // Read filesystem (return data)
int ReadFsOpt(BYTE *buf) const; // Read file system (optional data) int ReadFsOpt(vector<BYTE>&) const; // Read file system (optional data)
void WriteFs(int func, BYTE *buf); // File system write (execute) void WriteFs(int, vector<BYTE>&); // File system write (execute)
void WriteFsOpt(const BYTE *buf, int len); // File system write (optional data) void WriteFsOpt(const vector<BYTE>&, int); // File system write (optional data)
// Command handlers // Command handlers
void FS_InitDevice(BYTE *buf); // $40 - boot void FS_InitDevice(vector<BYTE>&); // $40 - boot
void FS_CheckDir(BYTE *buf); // $41 - directory check void FS_CheckDir(vector<BYTE>&); // $41 - directory check
void FS_MakeDir(BYTE *buf); // $42 - create directory void FS_MakeDir(vector<BYTE>&); // $42 - create directory
void FS_RemoveDir(BYTE *buf); // $43 - delete directory void FS_RemoveDir(vector<BYTE>&); // $43 - delete directory
void FS_Rename(BYTE *buf); // $44 - change filename void FS_Rename(vector<BYTE>&); // $44 - change filename
void FS_Delete(BYTE *buf); // $45 - delete file void FS_Delete(vector<BYTE>&); // $45 - delete file
void FS_Attribute(BYTE *buf); // $46 - get/set file attributes void FS_Attribute(vector<BYTE>&); // $46 - get/set file attributes
void FS_Files(BYTE *buf); // $47 - file search void FS_Files(vector<BYTE>&); // $47 - file search
void FS_NFiles(BYTE *buf); // $48 - find next file void FS_NFiles(vector<BYTE>&); // $48 - find next file
void FS_Create(BYTE *buf); // $49 - create file void FS_Create(vector<BYTE>&); // $49 - create file
void FS_Open(BYTE *buf); // $4A - open file void FS_Open(vector<BYTE>&); // $4A - open file
void FS_Close(BYTE *buf); // $4B - close file void FS_Close(vector<BYTE>&); // $4B - close file
void FS_Read(BYTE *buf); // $4C - read file void FS_Read(vector<BYTE>&); // $4C - read file
void FS_Write(BYTE *buf); // $4D - write file void FS_Write(vector<BYTE>&); // $4D - write file
void FS_Seek(BYTE *buf); // $4E - seek file void FS_Seek(vector<BYTE>&); // $4E - seek file
void FS_TimeStamp(BYTE *buf); // $4F - get/set file time void FS_TimeStamp(vector<BYTE>&); // $4F - get/set file time
void FS_GetCapacity(BYTE *buf); // $50 - get capacity void FS_GetCapacity(vector<BYTE>&); // $50 - get capacity
void FS_CtrlDrive(BYTE *buf); // $51 - drive status check/control void FS_CtrlDrive(vector<BYTE>&); // $51 - drive status check/control
void FS_GetDPB(BYTE *buf); // $52 - get DPB void FS_GetDPB(vector<BYTE>&); // $52 - get DPB
void FS_DiskRead(BYTE *buf); // $53 - read sector void FS_DiskRead(vector<BYTE>&); // $53 - read sector
void FS_DiskWrite(BYTE *buf); // $54 - write sector void FS_DiskWrite(vector<BYTE>&); // $54 - write sector
void FS_Ioctrl(BYTE *buf); // $55 - IOCTRL void FS_Ioctrl(vector<BYTE>&); // $55 - IOCTRL
void FS_Flush(BYTE *buf); // $56 - flush cache void FS_Flush(vector<BYTE>&); // $56 - flush cache
void FS_CheckMedia(BYTE *buf); // $57 - check media void FS_CheckMedia(vector<BYTE>&); // $57 - check media
void FS_Lock(BYTE *buf); // $58 - get exclusive control void FS_Lock(vector<BYTE>&); // $58 - get exclusive control
CFileSys fs; // File system accessor CFileSys fs; // File system accessor
DWORD fsresult = 0; // File system access result code 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 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 DWORD fsoptlen = 0; // File system access buffer size
}; };

View File

@ -41,6 +41,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h"
#include "../rasutil.h" #include "../rasutil.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "scsi_printer.h" #include "scsi_printer.h"
@ -48,6 +49,7 @@
using namespace std; using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
using namespace ras_util; using namespace ras_util;
using namespace scsi_command_util;
SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP") SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP")
{ {
@ -143,18 +145,13 @@ void SCSIPrinter::Print()
{ {
CheckReservation(); CheckReservation();
uint32_t length = ctrl->cmd[2]; uint32_t length = GetInt24(ctrl->cmd, 2);
length <<= 8;
length |= ctrl->cmd[3];
length <<= 8;
length |= ctrl->cmd[4];
LOGTRACE("Receiving %d byte(s) to be printed", length) LOGTRACE("Receiving %d byte(s) to be printed", length)
// TODO This device suffers from the statically allocated buffer size, if (length > controller->GetBufferSize()) {
// see https://github.com/akuker/RASCSI/issues/669 LOGERROR("%s", string("Transfer buffer overflow: Buffer size is " + to_string(controller->GetBufferSize()) +
if (length > (uint32_t)ctrl->bufsize) { " bytes, " + to_string(length) + " bytes expected").c_str())
LOGERROR("Transfer buffer overflow")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
@ -217,7 +214,7 @@ void SCSIPrinter::StopPrint()
TestUnitReady(); TestUnitReady();
} }
bool SCSIPrinter::WriteByteSequence(BYTE *buf, uint32_t length) bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
{ {
if (fd == -1) { if (fd == -1) {
strcpy(filename, TMP_FILE_PATTERN); 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) 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; return num_written == length;
} }

View File

@ -42,7 +42,7 @@ public:
void SendDiagnostic() override; void SendDiagnostic() override;
void StopPrint(); void StopPrint();
bool WriteByteSequence(BYTE *, uint32_t) override; bool WriteByteSequence(vector<BYTE>&, uint32_t) override;
void CheckReservation(); void CheckReservation();
void DiscardReservation(); void DiscardReservation();
void Cleanup(); void Cleanup();

View File

@ -32,11 +32,6 @@ SCSICD::SCSICD(const unordered_set<uint32_t>& sector_sizes) : Disk("SCCD")
dispatcher.Add(scsi_command::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification); dispatcher.Add(scsi_command::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
} }
SCSICD::~SCSICD()
{
ClearTrack();
}
bool SCSICD::Dispatch(scsi_command cmd) bool SCSICD::Dispatch(scsi_command cmd)
{ {
// The superclass class handles the less specific commands // The superclass class handles the less specific commands
@ -97,8 +92,10 @@ void SCSICD::Open(const Filepath& path)
super::Open(path); super::Open(path);
FileSupport::SetPath(path); FileSupport::SetPath(path);
SetUpCache(path);
// Set RAW flag // Set RAW flag
disk.dcache->SetRawMode(rawfile); cache->SetRawMode(rawfile);
// Attention if ready // Attention if ready
if (IsReady()) { if (IsReady()) {
@ -120,8 +117,8 @@ void SCSICD::OpenIso(const Filepath& path)
} }
// Get file size // Get file size
off_t size = fio.GetFileSize(); off_t file_size = fio.GetFileSize();
if (size < 0x800) { if (file_size < 0x800) {
fio.Close(); fio.Close();
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes"); 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 // Check if it is RAW format
array<BYTE, 12> sync; array<BYTE, 12> sync;
memset(sync.data(), 0xff, sync.size()); sync.fill(0xff);
sync[0] = 0x00; sync[0] = 0x00;
sync[11] = 0x00; sync[11] = 0x00;
rawfile = false; rawfile = false;
@ -160,16 +157,16 @@ void SCSICD::OpenIso(const Filepath& path)
if (rawfile) { if (rawfile) {
// Size must be a multiple of 2536 // 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 " 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 // Set the number of blocks
SetBlockCount((DWORD)(size / 0x930)); SetBlockCount((DWORD)(file_size / 0x930));
} else { } else {
// Set the number of blocks // Set the number of blocks
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount())); SetBlockCount((DWORD)(file_size >> GetSectorSizeShiftCount()));
} }
// Create only one data track // Create only one data track
@ -216,7 +213,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
void SCSICD::ReadToc() void SCSICD::ReadToc()
{ {
ctrl->length = ReadTocInternal(ctrl->cmd, ctrl->buffer); ctrl->length = ReadTocInternal(ctrl->cmd, controller->GetBuffer());
EnterDataInPhase(); EnterDataInPhase();
} }
@ -276,11 +273,8 @@ void SCSICD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changea
} }
} }
int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
{ {
assert(buf);
CheckReady(); CheckReady();
// Search for the track // 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 different from the current data track
if (dataindex != index) { if (dataindex != index) {
// Delete current disk cache (no need to save)
delete disk.dcache;
disk.dcache = nullptr;
// Reset the number of blocks // Reset the number of blocks
SetBlockCount(tracks[index]->GetBlocks()); SetBlockCount(tracks[index]->GetBlocks());
assert(GetBlockCount() > 0); assert(GetBlockCount() > 0);
@ -306,8 +296,9 @@ int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
// Recreate the disk cache // Recreate the disk cache
Filepath path; Filepath path;
tracks[index]->GetPath(path); tracks[index]->GetPath(path);
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount()); // Re-assign disk cache (no need to save)
disk.dcache->SetRawMode(rawfile); cache.reset(new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount()));
cache->SetRawMode(rawfile);
// Reset data index // Reset data index
dataindex = 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); 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(); CheckReady();
@ -327,9 +318,8 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
assert(tracks[0]); assert(tracks[0]);
// Get allocation length, clear buffer // Get allocation length, clear buffer
int length = cdb[7] << 8; int length = GetInt16(cdb, 7);
length |= cdb[8]; fill_n(buf.data(), length, 0);
memset(buf, 0, length);
// Get MSF Flag // Get MSF Flag
bool msf = cdb[1] & 0x02; bool msf = cdb[1] & 0x02;
@ -365,7 +355,7 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
if (msf) { if (msf) {
LBAtoMSF(lba, &buf[8]); LBAtoMSF(lba, &buf[8]);
} else { } else {
SetInt16(&buf[10], lba); SetInt16(buf, 10, lba);
} }
return length; return length;
} }
@ -380,34 +370,35 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, BYTE *buf)
assert(loop >= 1); assert(loop >= 1);
// Create header // Create header
SetInt16(&buf[0], (loop << 3) + 2); SetInt16(buf, 0, (loop << 3) + 2);
buf[2] = (BYTE)tracks[0]->GetTrackNo(); buf[2] = (BYTE)tracks[0]->GetTrackNo();
buf[3] = (BYTE)last; buf[3] = (BYTE)last;
buf += 4;
int offset = 4;
// Loop.... // Loop....
for (int i = 0; i < loop; i++) { for (int i = 0; i < loop; i++) {
// ADR and Control // ADR and Control
if (tracks[index]->IsAudio()) { if (tracks[index]->IsAudio()) {
// audio track // audio track
buf[1] = 0x10; buf[offset + 1] = 0x10;
} else { } else {
// data track // data track
buf[1] = 0x14; buf[offset + 1] = 0x14;
} }
// track number // track number
buf[2] = (BYTE)tracks[index]->GetTrackNo(); buf[offset + 2] = (BYTE)tracks[index]->GetTrackNo();
// track address // track address
if (msf) { if (msf) {
LBAtoMSF(tracks[index]->GetFirst(), &buf[4]); LBAtoMSF(tracks[index]->GetFirst(), &buf[offset + 4]);
} else { } else {
SetInt16(&buf[6], tracks[index]->GetFirst()); SetInt16(buf, offset + 6, tracks[index]->GetFirst());
} }
// Advance buffer pointer and index // Advance buffer pointer and index
buf += 8; offset += 8;
index++; index++;
} }

View File

@ -28,7 +28,7 @@ class SCSICD : public Disk, public ScsiMmcCommands, public FileSupport
public: public:
explicit SCSICD(const unordered_set<uint32_t>&); explicit SCSICD(const unordered_set<uint32_t>&);
~SCSICD() override; ~SCSICD() override = default;
SCSICD(SCSICD&) = delete; SCSICD(SCSICD&) = delete;
SCSICD& operator=(const SCSICD&) = delete; SCSICD& operator=(const SCSICD&) = delete;
@ -38,7 +38,7 @@ public:
// Commands // Commands
vector<byte> InquiryInternal() const override; 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: protected:
@ -51,7 +51,7 @@ private:
Dispatcher<SCSICD> dispatcher; 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 AddCDROMPage(map<int, vector<byte>>&, bool) const;
void AddCDDAPage(map<int, vector<byte>>&, bool) const; void AddCDDAPage(map<int, vector<byte>>&, bool) const;

View File

@ -30,7 +30,7 @@ SCSIHD::SCSIHD(const unordered_set<uint32_t>& sector_sizes, bool removable, scsi
SetSectorSizes(sector_sizes); 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 // 2TB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) { if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
@ -60,6 +60,8 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size)
Disk::Open(path); Disk::Open(path);
FileSupport::SetPath(path); FileSupport::SetPath(path);
SetUpCache(path, image_offset);
} }
void SCSIHD::Open(const Filepath& path) void SCSIHD::Open(const Filepath& path)
@ -73,17 +75,17 @@ void SCSIHD::Open(const Filepath& path)
} }
// Get file size // Get file size
off_t size = fio.GetFileSize(); off_t file_size = fio.GetFileSize();
fio.Close(); fio.Close();
// Sector size (default 512 bytes) and number of blocks // Sector size (default 512 bytes) and number of blocks
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount())); SetBlockCount((DWORD)(file_size >> GetSectorSizeShiftCount()));
// Effective size must be a multiple of the sector size // 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 vector<byte> SCSIHD::InquiryInternal() const
@ -91,7 +93,7 @@ vector<byte> SCSIHD::InquiryInternal() const
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level, IsRemovable()); 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()); scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
} }

View File

@ -31,13 +31,13 @@ public:
SCSIHD(SCSIHD&) = delete; SCSIHD(SCSIHD&) = delete;
SCSIHD& operator=(const 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; void Open(const Filepath&) override;
// Commands // Commands
vector<byte> InquiryInternal() const 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;
void AddFormatPage(map<int, vector<byte>>&, bool) const override; void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override; void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;

View File

@ -30,7 +30,7 @@ const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static inline int getWordLE(const BYTE *b) 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 // 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) void SCSIHD_NEC::Open(const Filepath& path)
@ -54,18 +54,18 @@ void SCSIHD_NEC::Open(const Filepath& path)
} }
// Get file size // Get file size
off_t size = fio.GetFileSize(); off_t file_size = fio.GetFileSize();
// NEC root sector // NEC root sector
array<BYTE, 512> 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(); fio.Close();
throw io_exception("Can't read NEC hard disk file root sector"); throw io_exception("Can't read NEC hard disk file root sector");
} }
fio.Close(); fio.Close();
// Effective size must be a multiple of 512 // Effective size must be a multiple of 512
size = (size / 512) * 512; file_size = (file_size / 512) * 512;
int image_size = 0; int image_size = 0;
int sector_size = 0; int sector_size = 0;
@ -75,18 +75,18 @@ void SCSIHD_NEC::Open(const Filepath& path)
// PC-9801-55 NEC genuine? // PC-9801-55 NEC genuine?
if (const char *ext = path.GetFileExt(); !strcasecmp(ext, ".hdn")) { if (const char *ext = path.GetFileExt(); !strcasecmp(ext, ".hdn")) {
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings // Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
disk.image_offset = 0; image_offset = 0;
image_size = (int)size; image_size = (int)file_size;
sector_size = 512; sector_size = 512;
sectors = 25; sectors = 25;
heads = 8; heads = 8;
cylinders = (int)(size >> 9); cylinders = (int)(file_size >> 9);
cylinders >>= 3; cylinders >>= 3;
cylinders /= 25; cylinders /= 25;
} }
// Anex86 HD image? // Anex86 HD image?
else if (!strcasecmp(ext, ".hdi")) { else if (!strcasecmp(ext, ".hdi")) {
disk.image_offset = getDwordLE(&root_sector[8]); image_offset = getDwordLE(&root_sector[8]);
image_size = getDwordLE(&root_sector[12]); image_size = getDwordLE(&root_sector[12]);
sector_size = getDwordLE(&root_sector[16]); sector_size = getDwordLE(&root_sector[16]);
sectors = getDwordLE(&root_sector[20]); sectors = getDwordLE(&root_sector[20]);
@ -96,7 +96,7 @@ void SCSIHD_NEC::Open(const Filepath& path)
// T98Next HD image? // T98Next HD image?
else if (!strcasecmp(ext, ".nhd")) { else if (!strcasecmp(ext, ".nhd")) {
if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) { 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]); cylinders = getDwordLE(&root_sector[0x114]);
heads = getWordLE(&root_sector[0x118]); heads = getWordLE(&root_sector[0x118]);
sectors = getWordLE(&root_sector[0x11a]); sectors = getWordLE(&root_sector[0x11a]);
@ -113,24 +113,23 @@ void SCSIHD_NEC::Open(const Filepath& path)
} }
// Image size consistency check // 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"); throw io_exception("Image size consistency check failed");
} }
// Calculate sector size // Calculate sector size
for (size = 16; size > 0; --size) { for (file_size = 16; file_size > 0; --file_size) {
if ((1 << size) == sector_size) if ((1 << file_size) == sector_size)
break; break;
} }
if (size <= 0 || size > 16) { if (file_size <= 0 || file_size > 16) {
throw io_exception("Invalid NEC disk size"); throw io_exception("Invalid NEC disk size");
} }
SetSectorSizeShiftCount((uint32_t)size); SetSectorSizeShiftCount((uint32_t)file_size);
// Number of blocks SetBlockCount(image_size >> GetSectorSizeShiftCount());
SetBlockCount(image_size >> disk.size);
FinalizeSetup(path, size); FinalizeSetup(path, file_size, image_offset);
} }
vector<byte> SCSIHD_NEC::InquiryInternal() const 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); SetInt16(buf, 0x0a, sectors);
// Set the number of bytes in the physical sector // 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) // Set removable attributes (remains of the old days)

View File

@ -13,9 +13,14 @@
// [ SCSI NEC "Genuine" Hard Disk] // [ SCSI NEC "Genuine" Hard Disk]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "scsihd.h" #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 class SCSIHD_NEC : public SCSIHD
{ {
static const unordered_set<uint32_t> sector_sizes;
public: public:
explicit SCSIHD_NEC() : SCSIHD(sector_sizes, false) {} SCSIHD_NEC() : SCSIHD(sector_sizes, false) {}
~SCSIHD_NEC() override = default; ~SCSIHD_NEC() override = default;
SCSIHD_NEC(SCSIHD_NEC&) = delete; SCSIHD_NEC(SCSIHD_NEC&) = delete;
SCSIHD_NEC& operator=(const 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; vector<byte> InquiryInternal() const override;
@ -43,6 +46,11 @@ public:
private: private:
static const unordered_set<uint32_t> sector_sizes;
// Image file offset (NEC only)
off_t image_offset = 0;
// Geometry data // Geometry data
int cylinders = 0; int cylinders = 0;
int heads = 0; int heads = 0;

View File

@ -7,11 +7,9 @@
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker // 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. // See LICENSE file in the project root folder.
// //
// [ SCSI Magneto-Optical Disk]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "fileio.h" #include "fileio.h"
@ -21,11 +19,18 @@
using namespace scsi_command_util; using namespace scsi_command_util;
SCSIMO::SCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries) SCSIMO::SCSIMO(const unordered_set<uint32_t>& sector_sizes) : Disk("SCMO")
: Disk("SCMO")
{ {
SetSectorSizes(sector_sizes); 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) void SCSIMO::Open(const Filepath& path)
@ -40,15 +45,14 @@ void SCSIMO::Open(const Filepath& path)
} }
// Get file size // Get file size
off_t size = fio.GetFileSize(); off_t file_size = fio.GetFileSize();
fio.Close(); fio.Close();
// For some priorities there are hard-coded, well-defined sector sizes and block counts // For some capacities there are hard-coded, well-defined sector sizes and block counts
// TODO Find a more flexible solution if (!SetGeometryForCapacity(file_size)) {
if (!SetGeometryForCapacity(size)) {
// Sector size (default 512 bytes) and number of blocks // Sector size (default 512 bytes) and number of blocks
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount(size >> GetSectorSizeShiftCount()); SetBlockCount(file_size >> GetSectorSizeShiftCount());
} }
SetReadOnly(false); SetReadOnly(false);
@ -58,6 +62,8 @@ void SCSIMO::Open(const Filepath& path)
Disk::Open(path); Disk::Open(path);
FileSupport::SetPath(path); FileSupport::SetPath(path);
SetUpCache(path);
// Attention if ready // Attention if ready
if (IsReady()) { if (IsReady()) {
SetAttn(true); SetAttn(true);
@ -94,7 +100,7 @@ void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
// Do not report update blocks // 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()); scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
} }

View File

@ -5,12 +5,10 @@
// //
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp) // Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker // 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. // See LICENSE file in the project root folder.
//
// [ SCSI Magneto-Optical Disk]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -20,11 +18,13 @@
#include "file_support.h" #include "file_support.h"
#include "filepath.h" #include "filepath.h"
using Geometry = pair<uint32_t, uint32_t>;
class SCSIMO : public Disk, public FileSupport class SCSIMO : public Disk, public FileSupport
{ {
public: public:
SCSIMO(const unordered_set<uint32_t>&, const unordered_map<uint64_t, Geometry>&); explicit SCSIMO(const unordered_set<uint32_t>&);
~SCSIMO() override = default; ~SCSIMO() override = default;
SCSIMO(SCSIMO&) = delete; SCSIMO(SCSIMO&) = delete;
SCSIMO& operator=(const SCSIMO&) = delete; SCSIMO& operator=(const SCSIMO&) = delete;
@ -32,7 +32,7 @@ public:
void Open(const Filepath&) override; void Open(const Filepath&) override;
vector<byte> InquiryInternal() const 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: protected:
@ -44,7 +44,6 @@ private:
void AddOptionPage(map<int, vector<byte>>&, bool) const; void AddOptionPage(map<int, vector<byte>>&, bool) const;
void SetGeometries(const unordered_map<uint64_t, Geometry>& g) { geometries = g; }
bool SetGeometryForCapacity(uint64_t); bool SetGeometryForCapacity(uint64_t);
// The mapping of supported capacities to block sizes and block counts, empty if there is no capacity restriction // The mapping of supported capacities to block sizes and block counts, empty if there is no capacity restriction

View File

@ -42,10 +42,6 @@ bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
break; break;
case OpenMode::ReadWrite: 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); handle = open(fname, O_RDWR | omode);
break; break;
@ -115,7 +111,7 @@ off_t Fileio::GetFileSize() const
assert(handle >= 0); assert(handle >= 0);
// Get file position in 64bit // Get file position in 64bit
off_t cur = GetFilePos(); off_t cur = lseek(handle, 0, SEEK_CUR);
// Get file size in64bitで // Get file size in64bitで
off_t end = lseek(handle, 0, SEEK_END); off_t end = lseek(handle, 0, SEEK_END);
@ -126,14 +122,6 @@ off_t Fileio::GetFileSize() const
return end; return end;
} }
off_t Fileio::GetFilePos() const
{
assert(handle >= 0);
// Get file position in 64bit
return lseek(handle, 0, SEEK_CUR);
}
void Fileio::Close() void Fileio::Close()
{ {
if (handle != -1) { if (handle != -1) {

View File

@ -35,7 +35,6 @@ public:
bool Read(BYTE *buffer, int size) const; bool Read(BYTE *buffer, int size) const;
bool Write(const BYTE *buffer, int size) const; bool Write(const BYTE *buffer, int size) const;
off_t GetFileSize() const; off_t GetFileSize() const;
off_t GetFilePos() const;
void Close(); void Close();
private: private:

View File

@ -31,44 +31,40 @@ using namespace std;
// imported from bcm_host.c // 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) { if (FILE *fp = fopen(filename, "rb"); fp) {
fseek(fp, offset, SEEK_SET); fseek(fp, offset, SEEK_SET);
if (BYTE buf[4]; fread(buf, 1, sizeof buf, fp) == sizeof buf) { if (array<BYTE, 4> buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) {
address = address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0;
buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
} }
fclose(fp); fclose(fp);
} }
return address; 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) { if (address == 0) {
address = get_dt_ranges("/proc/device-tree/soc/ranges", 8); address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
} }
address = (address == (DWORD)~0) ? 0x20000000 : address; address = (address == (uint32_t)~0) ? 0x20000000 : address;
#if 0
printf("Peripheral address : 0x%lx\n", address);
#endif
return address; return address;
} }
#endif #endif
#ifdef __NetBSD__ #ifdef __NetBSD__
// Assume the Raspberry Pi series and estimate the address from CPU // 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]; array<char, 1024> buf;
size_t len = sizeof(buf); size_t len = buf.size();
DWORD address; DWORD address;
if (sysctlbyname("hw.model", buf, &len, NULL, 0) || if (sysctlbyname("hw.model", buf.data(), &len, NULL, 0) ||
strstr(buf, "ARM1176JZ-S") != buf) { strstr(buf, "ARM1176JZ-S") != buf.data()) {
// Failed to get CPU model || Not BCM2835 // Failed to get CPU model || Not BCM2835
// use the address of BCM283[67] // use the address of BCM283[67]
address = 0x3f000000; address = 0x3f000000;
@ -79,7 +75,7 @@ DWORD bcm_host_get_peripheral_address(void)
printf("Peripheral address : 0x%lx\n", address); printf("Peripheral address : 0x%lx\n", address);
return address; return address;
} }
#endif // __NetBSD__ #endif
bool GPIOBUS::Init(mode_e mode) bool GPIOBUS::Init(mode_e mode)
{ {
@ -91,11 +87,11 @@ bool GPIOBUS::Init(mode_e mode)
#else #else
int i; int i;
#ifdef USE_SEL_EVENT_ENABLE #ifdef USE_SEL_EVENT_ENABLE
struct epoll_event ev; epoll_event ev = {};
#endif #endif
// Get the base address // Get the base address
baseaddr = (DWORD)bcm_host_get_peripheral_address(); baseaddr = (uint32_t)bcm_host_get_peripheral_address();
// Open /dev/mem // Open /dev/mem
int fd = open("/dev/mem", O_RDWR | O_SYNC); int fd = open("/dev/mem", O_RDWR | O_SYNC);
@ -232,7 +228,6 @@ bool GPIOBUS::Init(mode_e mode)
// epoll initialization // epoll initialization
epfd = epoll_create(1); epfd = epoll_create(1);
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN | EPOLLPRI; ev.events = EPOLLIN | EPOLLPRI;
ev.data.fd = selevreq.fd; ev.data.fd = selevreq.fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev); 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() bool GPIOBUS::PollSelectEvent()
{ {
// clear errno
errno = 0; errno = 0;
struct epoll_event epev;
struct gpioevent_data gpev;
if (epoll_wait(epfd, &epev, 1, -1) <= 0) { if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) {
LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__) LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__)
return false; return false;
} }
if (read(selevreq.fd, &gpev, sizeof(gpev)) < 0) { if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
LOGWARN("%s read failed", __PRETTY_FUNCTION__) LOGWARN("%s read failed", __PRETTY_FUNCTION__)
return false; return false;
} }
return true; return true;
} }
@ -1054,7 +1046,7 @@ void GPIOBUS::ClearSelectEvent()
// Signal table // Signal table
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const int GPIOBUS::SignalTable[19] = { const array<int, 19> GPIOBUS::SignalTable = {
PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3,
PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP,
PIN_SEL,PIN_ATN, PIN_RST, PIN_ACK, PIN_SEL,PIN_ATN, PIN_RST, PIN_ACK,
@ -1077,9 +1069,9 @@ void GPIOBUS::MakeTable(void)
array<bool, 256> tblParity; array<bool, 256> tblParity;
// Create parity table // Create parity table
for (int i = 0; i < 0x100; i++) { for (uint32_t i = 0; i < 0x100; i++) {
auto bits = (DWORD)i; uint32_t bits = i;
DWORD parity = 0; uint32_t parity = 0;
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
parity ^= bits & 1; parity ^= bits & 1;
bits >>= 1; bits >>= 1;
@ -1090,11 +1082,16 @@ void GPIOBUS::MakeTable(void)
#if SIGNAL_CONTROL_MODE == 0 #if SIGNAL_CONTROL_MODE == 0
// Mask and setting data generation // Mask and setting data generation
memset(tblDatMsk, 0xff, sizeof(tblDatMsk)); for (auto& tbl : tblDatMsk) {
memset(tblDatSet, 0x00, sizeof(tblDatSet)); tbl.fill(-1);
for (int i = 0; i < 0x100; i++) { }
for (auto& tbl : tblDatSet) {
tbl.fill(0);
}
for (uint32_t i = 0; i < 0x100; i++) {
// Bit string for inspection // Bit string for inspection
auto bits = (DWORD)i; uint32_t bits = i;
// Get parity // Get parity
if (tblParity[i]) { if (tblParity[i]) {
@ -1119,14 +1116,11 @@ void GPIOBUS::MakeTable(void)
} }
} }
#else #else
// Mask and setting data generation for (uint32_t i = 0; i < 0x100; i++) {
memset(tblDatMsk, 0x00, sizeof(tblDatMsk)); // Bit string for inspection
memset(tblDatSet, 0x00, sizeof(tblDatSet)); uint32_t bits = i;
for (int i = 0; i < 0x100; i++) {
// bit string for inspection
DWORD bits = (DWORD)i;
// get parity // Get parity
if (tblParity[i]) { if (tblParity[i]) {
bits |= (1 << 8); bits |= (1 << 8);
} }
@ -1137,8 +1131,8 @@ void GPIOBUS::MakeTable(void)
#endif #endif
// Create GPIO register information // Create GPIO register information
DWORD gpclr = 0; uint32_t gpclr = 0;
DWORD gpset = 0; uint32_t gpset = 0;
for (int j = 0; j < 9; j++) { for (int j = 0; j < 9; j++) {
if (bits & 1) { if (bits & 1) {
gpset |= (1 << pintbl[j]); gpset |= (1 << pintbl[j]);
@ -1400,11 +1394,10 @@ void GPIOBUS::DrvConfig(DWORD drive)
BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data) BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
{ {
// Selection Phase // Selection Phase
if (GetPinRaw(raw_data, PIN_SEL)) if (GetPinRaw(raw_data, PIN_SEL)) {
{ if(GetPinRaw(raw_data, PIN_IO)) {
if(GetPinRaw(raw_data, PIN_IO)){
return BUS::phase_t::reselection; return BUS::phase_t::reselection;
}else{ } else{
return BUS::phase_t::selection; return BUS::phase_t::selection;
} }
} }
@ -1415,7 +1408,7 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
} }
// Get target phase from bus signal line // 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_CD) ? 0x02 : 0x00;
mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00; mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00;
return GetPhase(mci); return GetPhase(mci);

View File

@ -13,6 +13,7 @@
#include "config.h" #include "config.h"
#include "scsi.h" #include "scsi.h"
#include <array>
#ifdef __linux #ifdef __linux
#include <linux/gpio.h> #include <linux/gpio.h>
@ -40,6 +41,8 @@
#error Invalid connection type or none specified #error Invalid connection type or none specified
#endif #endif
using namespace std; //NOSONAR Not relevant for rascsi
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Signal control logic and pin assignment customization // Signal control logic and pin assignment customization
@ -455,7 +458,9 @@ private:
mode_e actmode = mode_e::TARGET; // Operation mode mode_e actmode = mode_e::TARGET; // Operation mode
#if !defined(__x86_64__) && !defined(__X86__)
uint32_t baseaddr = 0; // Base address uint32_t baseaddr = 0; // Base address
#endif
int rpitype = 0; // Type of Raspberry Pi int rpitype = 0; // Type of Raspberry Pi
@ -463,7 +468,9 @@ private:
volatile uint32_t *pads = nullptr; // PADS register volatile uint32_t *pads = nullptr; // PADS register
#if !defined(__x86_64__) && !defined(__X86__)
volatile uint32_t *level = nullptr; // GPIO input level volatile uint32_t *level = nullptr; // GPIO input level
#endif
volatile uint32_t *irpctl = nullptr; // Interrupt control register volatile uint32_t *irpctl = nullptr; // Interrupt control register
@ -477,11 +484,13 @@ private:
volatile uint32_t giccpmr; // GICC priority setting volatile uint32_t giccpmr; // GICC priority setting
#if !defined(__x86_64__) && !defined(__X86__)
volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register
#endif
volatile uint32_t *gicc = nullptr; // GIC CPU interface register 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 uint32_t signals = 0; // All bus signals
@ -492,15 +501,15 @@ private:
#endif // USE_SEL_EVENT_ENABLE #endif // USE_SEL_EVENT_ENABLE
#if SIGNAL_CONTROL_MODE == 0 #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 #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 #endif
static const int SignalTable[19]; // signal table static const array<int, 19> SignalTable; // signal table
}; };

View File

@ -17,155 +17,154 @@ using namespace std;
Localizer::Localizer() Localizer::Localizer()
{ {
// Positional string arguments are %1, %2, %3 Add(LocalizationKey::ERROR_AUTHENTICATION, "en", "Authentication failed");
Add(ERROR_AUTHENTICATION, "en", "Authentication failed"); Add(LocalizationKey::ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
Add(ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen"); Add(LocalizationKey::ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades");
Add(ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades"); Add(LocalizationKey::ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
Add(ERROR_AUTHENTICATION, "fr", "Authentification éronnée"); Add(LocalizationKey::ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
Add(ERROR_AUTHENTICATION, "es", "Fallo de autentificación"); Add(LocalizationKey::ERROR_OPERATION, "en", "Unknown operation");
Add(ERROR_OPERATION, "en", "Unknown operation"); Add(LocalizationKey::ERROR_OPERATION, "de", "Unbekannte Operation");
Add(ERROR_OPERATION, "de", "Unbekannte Operation"); Add(LocalizationKey::ERROR_OPERATION, "sv", "Okänd operation");
Add(ERROR_OPERATION, "sv", "Okänd operation"); Add(LocalizationKey::ERROR_OPERATION, "fr", "Opération inconnue");
Add(ERROR_OPERATION, "fr", "Opération inconnue"); Add(LocalizationKey::ERROR_OPERATION, "es", "Operación desconocida");
Add(ERROR_OPERATION, "es", "Operación desconocida"); Add(LocalizationKey::ERROR_LOG_LEVEL, "en", "Invalid log level %1");
Add(ERROR_LOG_LEVEL, "en", "Invalid log level %1"); Add(LocalizationKey::ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
Add(ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1"); Add(LocalizationKey::ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
Add(ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1"); Add(LocalizationKey::ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
Add(ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1"); Add(LocalizationKey::ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
Add(ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido"); Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
Add(ERROR_MISSING_DEVICE_ID, "en", "Missing device ID"); Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
Add(ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID"); Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas");
Add(ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas"); Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
Add(ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante"); Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
Add(ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo"); Add(LocalizationKey::ERROR_MISSING_FILENAME, "en", "Missing filename");
Add(ERROR_MISSING_FILENAME, "en", "Missing filename"); Add(LocalizationKey::ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
Add(ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname"); Add(LocalizationKey::ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas"); Add(LocalizationKey::ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
Add(ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant"); Add(LocalizationKey::ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
Add(ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo"); Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
Add(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(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(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(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(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(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(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(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(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(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(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(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(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(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved"); Add(LocalizationKey::ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert"); Add(LocalizationKey::ERROR_RESERVED_ID, "sv", "Enhets-id %1 är reserverat");
Add(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(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(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(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(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(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(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(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(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(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(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(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(ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2"); Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1"); Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1"); Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1"); Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
Add(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(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(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(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(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(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(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(ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2"); Add(LocalizationKey::ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
Add(ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2"); Add(LocalizationKey::ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2");
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2"); Add(LocalizationKey::ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
Add(ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée"); Add(LocalizationKey::ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
Add(ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2"); Add(LocalizationKey::ERROR_DETACH, "en", "Couldn't detach device");
Add(ERROR_DETACH, "en", "Couldn't detach device"); Add(LocalizationKey::ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
Add(ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden"); Add(LocalizationKey::ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten");
Add(ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten"); Add(LocalizationKey::ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo");
Add(ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo"); Add(LocalizationKey::ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected"); Add(LocalizationKey::ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
Add(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(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(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(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(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(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(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(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(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(ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
Add(ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
Add(ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
Add(ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
Add(ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'"); Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
Add(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(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(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(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(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(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(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(ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2"); Add(LocalizationKey::ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
Add(ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2"); Add(LocalizationKey::ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
Add(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(ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2"); Add(LocalizationKey::ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
Add(ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes"); Add(LocalizationKey::ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
Add(ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes"); Add(LocalizationKey::ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
Add(ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte"); Add(LocalizationKey::ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
Add(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(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(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(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(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(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(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(ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller"); Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
Add(ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden"); Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "sv", "Kunde ej skapa SCSI-gränssnitt");
Add(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(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(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(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(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(ERROR_INVALID_ID, "es", "ID de dispositivo inválido %1 (0-%2)"); Add(LocalizationKey::ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
Add(ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)"); Add(LocalizationKey::ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
Add(ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)"); Add(LocalizationKey::ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)");
Add(ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)"); Add(LocalizationKey::ERROR_INVALID_LUN, "es", "LUN invalido %1 (0-%2)");
Add(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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");
Add(ERROR_OPERATION_DENIED_READY, "es", "%1 operación denegada, %2 no está listo");
} }
void Localizer::Add(LocalizationKey key, const string& locale, string_view value) 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; auto messages = it->second;
if (messages.empty()) { 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]; string message = messages[key];

View File

@ -17,7 +17,7 @@
using namespace std; //NOSONAR Not relevant for rascsi using namespace std; //NOSONAR Not relevant for rascsi
enum LocalizationKey { enum class LocalizationKey {
ERROR_AUTHENTICATION, ERROR_AUTHENTICATION,
ERROR_OPERATION, ERROR_OPERATION,
ERROR_LOG_LEVEL, ERROR_LOG_LEVEL,

View File

@ -71,7 +71,7 @@ DeviceFactory device_factory;
ControllerManager controller_manager; ControllerManager controller_manager;
RascsiImage rascsi_image; RascsiImage rascsi_image;
RascsiResponse rascsi_response(&device_factory, &rascsi_image); RascsiResponse rascsi_response(&device_factory, &rascsi_image);
SocketConnector socket_connector; const SocketConnector socket_connector;
void DetachAll(); void DetachAll();
static void *MonThread(void *); static void *MonThread(void *);
@ -139,9 +139,8 @@ bool InitService(int port)
} }
// Create socket for monitor // Create socket for monitor
sockaddr_in server; sockaddr_in server = {};
monsocket = socket(PF_INET, SOCK_STREAM, 0); monsocket = socket(PF_INET, SOCK_STREAM, 0);
memset(&server, 0, sizeof(server));
server.sin_family = PF_INET; server.sin_family = PF_INET;
server.sin_port = htons(port); server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY); 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(); const PbDeviceType type = pb_device.type();
if (controller_manager.GetDeviceByIdAndLun(id, unit) != nullptr) { 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) { if (unit >= ScsiController::LUN_MAX) {
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX)); return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX));
} }
string filename = GetParam(pb_device, "file"); 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); PrimaryDevice *device = device_factory.CreateDevice(type, filename, id);
if (device == nullptr) { if (device == nullptr) {
if (type == UNDEFINED) { if (type == UNDEFINED) {
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_TYPE, filename); return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
} }
else { 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())) { if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) {
device_factory.DeleteDevice(*device); 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 { else {
device_factory.DeleteDevice(*device); 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()) { if (file_support != nullptr && !device->IsRemovable() && filename.empty()) {
device_factory.DeleteDevice(*device); 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; Filepath filepath;
@ -461,7 +460,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) { if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
device_factory.DeleteDevice(*device); 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 { try {
@ -475,7 +474,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) { if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
device_factory.DeleteDevice(*device); 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); file_support->Open(filepath);
@ -484,7 +483,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
catch(const io_exception& e) { catch(const io_exception& e) {
device_factory.DeleteDevice(*device); 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()); 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)) { if (!device->Init(params)) {
device_factory.DeleteDevice(*device); 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); pthread_mutex_lock(&ctrl_mutex);
@ -518,7 +517,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!controller_manager.CreateScsiController(bus, device)) { if (!controller_manager.CreateScsiController(bus, device)) {
pthread_mutex_unlock(&ctrl_mutex); pthread_mutex_unlock(&ctrl_mutex);
return ReturnLocalizedError(context, ERROR_SCSI_CONTROLLER); return ReturnLocalizedError(context, LocalizationKey::ERROR_SCSI_CONTROLLER);
} }
pthread_mutex_unlock(&ctrl_mutex); 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()) { for (const Device *d : device_factory.GetAllDevices()) {
// LUN 0 can only be detached if there is no other LUN anymore // LUN 0 can only be detached if there is no other LUN anymore
if (d->GetId() == device->GetId() && d->GetLun()) { 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)) { if (!controller_manager.FindController(id)->DeleteDevice(device)) {
pthread_mutex_unlock(&ctrl_mutex); pthread_mutex_unlock(&ctrl_mutex);
return ReturnLocalizedError(context, ERROR_DETACH); return ReturnLocalizedError(context, LocalizationKey::ERROR_DETACH);
} }
device_factory.DeleteDevice(*device); device_factory.DeleteDevice(*device);
pthread_mutex_unlock(&ctrl_mutex); 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) bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device, Device *device, bool dryRun)
{ {
if (!device->IsRemoved()) { 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()) { 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"); string filename = GetParam(pb_device, "file");
if (filename.empty()) { if (filename.empty()) {
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME); return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
} }
if (dryRun) { if (dryRun) {
@ -599,11 +598,11 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (pb_device.block_size()) { if (pb_device.block_size()) {
if (disk != nullptr&& disk->IsSectorSizeConfigurable()) { if (disk != nullptr&& disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) { 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 { 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(); string initial_filename = filepath.GetPath();
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) { 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); 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()); filepath.SetPath((rascsi_image.GetDefaultImageFolder() + "/" + filename).c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) { 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); file_support->Open(filepath);
} }
} }
catch(const io_exception& e) { //NOSONAR This exception is handled properly 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()); 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 // Check the Controller Number
if (id < 0) { if (id < 0) {
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID); return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_ID);
} }
if (id >= ControllerManager::DEVICE_MAX) { 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()) { 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 // Check the Unit Number
if (unit < 0 || unit >= AbstractController::LUN_MAX) { if (unit < 0 || unit >= ScsiController::LUN_MAX) {
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX - 1)); return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX - 1));
} }
if (operation == ATTACH) { if (operation == ATTACH) {
@ -732,13 +731,13 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
// Does the controller exist? // Does the controller exist?
if (!dryRun && controller_manager.FindController(id) == nullptr) { 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? // Does the unit exist?
PrimaryDevice *device = controller_manager.GetDeviceByIdAndLun(id, unit); PrimaryDevice *device = controller_manager.GetDeviceByIdAndLun(id, unit);
if (device == nullptr) { 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) { if (operation == DETACH) {
@ -746,18 +745,18 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
} }
if ((operation == START || operation == STOP) && !device->IsStoppable()) { 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()) { 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()) { 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()) { 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) { switch (operation) {
@ -824,7 +823,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
break; break;
default: default:
return ReturnLocalizedError(context, ERROR_OPERATION); return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION);
} }
return true; return true;
@ -915,8 +914,8 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
unit = 0; unit = 0;
} }
else if (!GetAsInt(id_spec.substr(0, separator_pos), id) || id < 0 || id > 7 || 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) { !GetAsInt(id_spec.substr(separator_pos + 1), unit) || unit < 0 || unit >= ScsiController::LUN_MAX) {
cerr << optarg << ": Invalid unit (0-" << (AbstractController::LUN_MAX - 1) << ")" << endl; cerr << optarg << ": Invalid unit (0-" << (ScsiController::LUN_MAX - 1) << ")" << endl;
return false; return false;
} }
@ -925,7 +924,7 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
void ShutDown(const CommandContext& context, const string& mode) { void ShutDown(const CommandContext& context, const string& mode) {
if (mode.empty()) { if (mode.empty()) {
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_MISSING); ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
return; return;
} }
@ -942,7 +941,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
// The root user has UID 0 // The root user has UID 0
if (getuid()) { if (getuid()) {
ReturnLocalizedError(context, ERROR_SHUTDOWN_PERMISSION); ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
return; return;
} }
@ -969,7 +968,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
} }
} }
else { 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); command.set_operation(ATTACH);
Localizer localizer; Localizer localizer;
CommandContext context(&socket_connector, &localizer, -1, locale); CommandContext context(socket_connector, localizer, -1, locale);
if (!ProcessCmd(context, command)) { if (!ProcessCmd(context, command)) {
return false; return false;
} }
@ -1179,13 +1178,13 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
} }
if (!access_token.empty() && access_token != GetParam(command, "token")) { 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())) { if (!PbOperation_IsValid(command.operation())) {
LOGERROR("Received unknown command with operation opcode %d", 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()) LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str())
@ -1196,7 +1195,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
case LOG_LEVEL: { case LOG_LEVEL: {
string log_level = GetParam(command, "level"); string log_level = GetParam(command, "level");
if (bool status = SetLogLevel(log_level); !status) { if (bool status = SetLogLevel(log_level); !status) {
ReturnLocalizedError(context, ERROR_LOG_LEVEL, log_level); ReturnLocalizedError(context, LocalizationKey::ERROR_LOG_LEVEL, log_level);
} }
else { else {
ReturnStatus(context); ReturnStatus(context);
@ -1256,7 +1255,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
case IMAGE_FILE_INFO: { case IMAGE_FILE_INFO: {
if (string filename = GetParam(command, "file"); filename.empty()) { if (string filename = GetParam(command, "file"); filename.empty()) {
ReturnLocalizedError(context, ERROR_MISSING_FILENAME); ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
} }
else { else {
auto image_file = make_unique<PbImageFile>(); auto image_file = make_unique<PbImageFile>();
@ -1267,7 +1266,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
socket_connector.SerializeMessage(context.fd, result); socket_connector.SerializeMessage(context.fd, result);
} }
else { else {
ReturnLocalizedError(context, ERROR_IMAGE_FILE_INFO); ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_FILE_INFO);
} }
} }
break; 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 // Set up the monitor socket to receive commands
listen(monsocket, 1); listen(monsocket, 1);
Localizer localizer;
while (true) { while (true) {
Localizer localizer; CommandContext context(socket_connector, localizer, -1, "");
CommandContext context(&socket_connector, &localizer, -1, "");
try { try {
PbCommand command; PbCommand command;

View File

@ -44,8 +44,7 @@ bool RascsiImage::CreateImageFolder(const CommandContext& context, const string&
string folder = filename.substr(0, filename_start); string folder = filename.substr(0, filename_start);
// Checking for existence first prevents an error if the top-level folder is a softlink // Checking for existence first prevents an error if the top-level folder is a softlink
struct stat st; if (struct stat st; stat(folder.c_str(), &st)) {
if (stat(folder.c_str(), &st)) {
std::error_code error; std::error_code error;
filesystem::create_directories(folder, error); filesystem::create_directories(folder, error);
if (error) { if (error) {

View File

@ -24,7 +24,7 @@ PbDeviceProperties *RascsiResponse::GetDeviceProperties(const Device *device)
{ {
auto properties = make_unique<PbDeviceProperties>().release(); 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_read_only(device->IsReadOnly());
properties->set_protectable(device->IsProtectable()); properties->set_protectable(device->IsProtectable());
properties->set_stoppable(device->IsStoppable()); properties->set_stoppable(device->IsStoppable());
@ -56,7 +56,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
type_properties->set_type(type); type_properties->set_type(type);
const PrimaryDevice *device = device_factory->CreateDevice(type, "", -1); const PrimaryDevice *device = device_factory->CreateDevice(type, "", -1);
type_properties->set_allocated_properties(GetDeviceProperties(device)); 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) 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_removed(device->IsRemoved());
status->set_locked(device->IsLocked()); 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()) { for (const auto& [key, value] : device->GetParams()) {
AddParam(*pb_device, key, value); 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()); GetImageFile(image_file, device->IsRemovable() && !device->IsReady() ? "" : filepath.GetPath());
pb_device->set_allocated_file(image_file); 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 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)); 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 (struct stat st; !stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
if (!stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
image_file->set_size(st.st_size); image_file->set_size(st.st_size);
return true; 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, 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) { 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; string folder_pattern_lower = folder_pattern;
transform(folder_pattern_lower.begin(), folder_pattern_lower.end(), folder_pattern_lower.begin(), ::tolower); transform(folder_pattern_lower.begin(), folder_pattern_lower.end(), folder_pattern_lower.begin(), ::tolower);
string file_pattern_lower = file_pattern; string file_pattern_lower = file_pattern;
transform(file_pattern_lower.begin(), file_pattern_lower.end(), file_pattern_lower.begin(), ::tolower); transform(file_pattern_lower.begin(), file_pattern_lower.end(), file_pattern_lower.begin(), ::tolower);
if (scan_depth-- >= 0) { DIR *d = opendir(folder.c_str());
if (DIR *d = opendir(folder.c_str()); d) { if (d == nullptr) {
const dirent *dir; return;
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);
}
string filename = folder + "/" + dir->d_name; const dirent *dir;
while ((dir = readdir(d))) {
if (struct stat st; dir->d_type == DT_REG && !stat(filename.c_str(), &st)) { 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 (!st.st_size) { if (is_supported_type && dir->d_name[0] != '.') {
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str()) string name_lower = dir->d_name;
continue; if (!file_pattern.empty()) {
} transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
} 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); 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, 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()); image_files_info->set_default_image_folder(rascsi_image->GetDefaultImageFolder());
server_info.set_allocated_image_files_info(image_files_info); 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) 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(); auto server_info = make_unique<PbServerInfo>().release();
server_info->set_allocated_version_info(GetVersionInfo(result)); 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 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 alloced 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); GetAvailableImages(result, *server_info, folder_pattern, file_pattern, scan_depth);
server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result)); 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 server_info->set_allocated_mapping_info(GetMappingInfo(result)); //NOSONAR The allocated memory is managed by protobuf
GetDevices(*server_info); //NOSONAR The alloced 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_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); result.set_status(true);
@ -461,11 +465,11 @@ PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth)
PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation, PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation,
const string& description) const 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_server_side_name(PbOperation_Name(operation));
meta_data->set_description(description); meta_data->set_description(description);
int ordinal = PbOperation_descriptor()->FindValueByName(PbOperation_Name(operation))->index(); 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]; return &(*operation_info.mutable_operations())[ordinal];
} }

View File

@ -18,6 +18,10 @@
#include "hal/gpiobus.h" #include "hal/gpiobus.h"
#include "hal/systimer.h" #include "hal/systimer.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include <iostream>
#include <array>
using namespace std;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
@ -380,7 +384,7 @@ int MessageIn()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int TestUnitReady(int id) int TestUnitReady(int id)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
// Result code initialization // Result code initialization
result = 0; result = 0;
@ -392,9 +396,8 @@ int TestUnitReady(int id)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x00; cmd[0] = 0x00;
if (!Command(cmd, 6)) { if (!Command(cmd.data(), 6)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -425,12 +428,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int RequestSense(int id, BYTE *buf) int RequestSense(int id, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -439,10 +441,9 @@ int RequestSense(int id, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x03; cmd[0] = 0x03;
cmd[4] = 0xff; cmd[4] = 0xff;
if (!Command(cmd, 6)) { if (!Command(cmd.data(), 6)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -486,12 +487,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int ModeSense(int id, BYTE *buf) int ModeSense(int id, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -500,11 +500,10 @@ int ModeSense(int id, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x1a; cmd[0] = 0x1a;
cmd[2] = 0x3f; cmd[2] = 0x3f;
cmd[4] = 0xff; cmd[4] = 0xff;
if (!Command(cmd, 6)) { if (!Command(cmd.data(), 6)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -548,12 +547,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int Inquiry(int id, BYTE *buf) int Inquiry(int id, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -562,10 +560,9 @@ int Inquiry(int id, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x12; cmd[0] = 0x12;
cmd[4] = 0xff; cmd[4] = 0xff;
if (!Command(cmd, 6)) { if (!Command(cmd.data(), 6)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -609,12 +606,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int ReadCapacity(int id, BYTE *buf) int ReadCapacity(int id, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -623,9 +619,8 @@ int ReadCapacity(int id, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 10);
cmd[0] = 0x25; cmd[0] = 0x25;
if (!Command(cmd, 10)) { if (!Command(cmd.data(), 10)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -669,12 +664,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -683,7 +677,6 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 10);
cmd[0] = 0x28; cmd[0] = 0x28;
cmd[2] = (BYTE)(bstart >> 24); cmd[2] = (BYTE)(bstart >> 24);
cmd[3] = (BYTE)(bstart >> 16); 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[5] = (BYTE)bstart;
cmd[7] = (BYTE)(blength >> 8); cmd[7] = (BYTE)(blength >> 8);
cmd[8] = (BYTE)blength; cmd[8] = (BYTE)blength;
if (!Command(cmd, 10)) { if (!Command(cmd.data(), 10)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -734,12 +727,11 @@ exit:
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
{ {
BYTE cmd[256]; array<BYTE, 256> cmd = {};
int count;
// Result code initialization // Result code initialization
result = 0; result = 0;
count = 0; int count = 0;
// SELECTION // SELECTION
if (!Selection(id)) { if (!Selection(id)) {
@ -748,7 +740,6 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
} }
// COMMAND // COMMAND
memset(cmd, 0x00, 10);
cmd[0] = 0x2a; cmd[0] = 0x2a;
cmd[2] = (BYTE)(bstart >> 24); cmd[2] = (BYTE)(bstart >> 24);
cmd[3] = (BYTE)(bstart >> 16); 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[5] = (BYTE)bstart;
cmd[7] = (BYTE)(blength >> 8); cmd[7] = (BYTE)(blength >> 8);
cmd[8] = (BYTE)blength; cmd[8] = (BYTE)blength;
if (!Command(cmd, 10)) { if (!Command(cmd.data(), 10)) {
result = -2; result = -2;
goto exit; goto exit;
} }
@ -833,6 +824,11 @@ int main(int argc, char* argv[])
exit(EINVAL); exit(EINVAL);
} }
#ifndef USE_SEL_EVENT_ENABLE
cerr << "Error: No RaSCSI hardware support" << endl;
exit(EXIT_FAILURE);
#endif
// Reset the SCSI bus // Reset the SCSI bus
Reset(); Reset();
@ -910,15 +906,15 @@ int main(int argc, char* argv[])
(buffer[2] << 8) | buffer[3]; (buffer[2] << 8) | buffer[3];
bnum++; bnum++;
printf("Number of blocks : %d Blocks\n", (int)bnum); printf("Number of blocks : %d Blocks\n", (int)bnum);
printf("Block length : %d B\n", (int)bsiz); printf("Block length : %d Bytes\n", (int)bsiz);
printf("Unit Capacity : %d MiB %d B\n", printf("Unit Capacity : %d MBytes %d Bytes\n",
(int)(bsiz * bnum / 1024 / 1024), (int)(bsiz * bnum / 1024 / 1024),
(int)(bsiz * bnum)); (int)(bsiz * bnum));
// Get the restore file size // Get the restore file size
if (restore) { if (restore) {
size = fio.GetFileSize(); 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)) { if (size > (off_t)(bsiz * bnum)) {
printf("(WARNING : File size is larger than disk size)"); printf("(WARNING : File size is larger than disk size)");
} else if (size < (off_t)(bsiz * bnum)) { } else if (size < (off_t)(bsiz * bnum)) {

View File

@ -20,10 +20,9 @@ using namespace rascsi_interface;
int SocketConnector::ReadCommand(PbCommand& command, int socket) const int SocketConnector::ReadCommand(PbCommand& command, int socket) const
{ {
// Wait for connection // Wait for connection
sockaddr_in client; sockaddr client = {};
socklen_t socklen = sizeof(client); socklen_t socklen = sizeof(client);
memset(&client, 0, socklen); int fd = accept(socket, &client, &socklen);
int fd = accept(socket, (sockaddr*)&client, &socklen);
if (fd < 0) { if (fd < 0) {
throw io_exception("accept() failed"); throw io_exception("accept() failed");
} }

View File

@ -10,23 +10,114 @@
#include "testing.h" #include "testing.h"
#include "controllers/abstract_controller.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) TEST(AbstractControllerTest, DeviceLunLifeCycle)
{ {
const int ID = 1; const int ID = 1;
const int LUN = 4; const int LUN = 4;
MockAbstractController controller(ID); 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_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_TRUE(controller.HasDeviceForLun(LUN));
EXPECT_FALSE(controller.HasDeviceForLun(0)); EXPECT_FALSE(controller.HasDeviceForLun(0));
EXPECT_EQ(&device, controller.GetDeviceForLun(LUN)); EXPECT_EQ(&device1, controller.GetDeviceForLun(LUN));
EXPECT_EQ(nullptr, controller.GetDeviceForLun(0)); EXPECT_EQ(nullptr, controller.GetDeviceForLun(0));
EXPECT_TRUE(controller.DeleteDevice(&device)); EXPECT_TRUE(controller.DeleteDevice(&device1));
EXPECT_FALSE(controller.HasLuns());
} }
TEST(AbstractControllerTest, ExtractInitiatorId) TEST(AbstractControllerTest, ExtractInitiatorId)
@ -45,9 +136,9 @@ TEST(AbstractControllerTest, GetOpcode)
{ {
MockAbstractController controller(0); 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()); EXPECT_EQ(0x12, (int)controller.GetOpcode());
} }
@ -57,8 +148,16 @@ TEST(AbstractControllerTest, GetLun)
MockAbstractController controller(0); 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()); EXPECT_EQ(LUN, controller.GetLun());
} }
TEST(AbstractControllerTest, Ctrl)
{
MockAbstractController controller(0);
EXPECT_FALSE(controller.HasValidLength());
}

View File

@ -12,6 +12,7 @@
#include "rascsi_version.h" #include "rascsi_version.h"
#include "devices/device.h" #include "devices/device.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include <unordered_map>
TEST(DeviceFactoryTest, GetTypeForFile) TEST(DeviceFactoryTest, GetTypeForFile)
{ {
@ -101,12 +102,64 @@ TEST(DeviceFactoryTest, GetSectorSizes)
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end()); 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) TEST(DeviceFactoryTest, UnknownDeviceType)
{ {
DeviceFactory device_factory; DeviceFactory device_factory;
PrimaryDevice *device = device_factory.CreateDevice(UNDEFINED, "test", -1); PrimaryDevice *device1 = device_factory.CreateDevice(UNDEFINED, "test", -1);
EXPECT_EQ(nullptr, device); 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) TEST(DeviceFactoryTest, SCHD_Device_Defaults)

View File

@ -13,7 +13,7 @@
class TestDevice final : public Device class TestDevice final : public Device
{ {
FRIEND_TEST(DeviceTest, GetSetParams); FRIEND_TEST(DeviceTest, Params);
FRIEND_TEST(DeviceTest, StatusCode); FRIEND_TEST(DeviceTest, StatusCode);
FRIEND_TEST(DeviceTest, Reset); FRIEND_TEST(DeviceTest, Reset);
FRIEND_TEST(DeviceTest, Start); FRIEND_TEST(DeviceTest, Start);
@ -102,7 +102,7 @@ TEST(DeviceTest, ProductData)
EXPECT_EQ("V P R ", device.GetPaddedName()); EXPECT_EQ("V P R ", device.GetPaddedName());
} }
TEST(DeviceTest, GetSetParams) TEST(DeviceTest, Params)
{ {
TestDevice device; TestDevice device;
unordered_map<string, string> params; unordered_map<string, string> params;

View File

@ -24,7 +24,7 @@ TEST(DiskTest, Rezero)
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRezero)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRezero));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, FormatUnit) TEST(DiskTest, FormatUnit)
@ -34,7 +34,7 @@ TEST(DiskTest, FormatUnit)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(6); vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception); EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
@ -42,10 +42,10 @@ TEST(DiskTest, FormatUnit)
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdFormat)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdFormat));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
controller.ctrl.cmd[1] = 0x10; cmd[1] = 0x10;
controller.ctrl.cmd[4] = 1; cmd[4] = 1;
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception); EXPECT_THROW(disk.Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
} }
@ -63,7 +63,7 @@ TEST(DiskTest, ReassignBlocks)
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReassign)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReassign));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, Seek) TEST(DiskTest, Seek)
@ -73,7 +73,7 @@ TEST(DiskTest, Seek)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(10); vector<int>& cmd = controller.InitCmd(10);
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSeek6), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
<< "SEEK(6) must fail for a medium with 0 blocks"; << "SEEK(6) must fail for a medium with 0 blocks";
@ -89,17 +89,17 @@ TEST(DiskTest, Seek)
disk.SetReady(true); disk.SetReady(true);
// Block count for SEEK(6) // Block count for SEEK(6)
controller.ctrl.cmd[4] = 1; cmd[4] = 1;
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek6)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek6));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
controller.ctrl.cmd[4] = 0; cmd[4] = 0;
// Block count for SEEK(10) // Block count for SEEK(10)
controller.ctrl.cmd[5] = 1; cmd[5] = 1;
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek10)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSeek10));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, ReadCapacity) TEST(DiskTest, ReadCapacity)
@ -109,7 +109,7 @@ TEST(DiskTest, ReadCapacity)
controller.AddDevice(&disk); 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
<< "Neithed READ CAPACITY(16) nor READ LONG(16)"; << "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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
<< "READ CAPACITY(10) must fail because drive is not ready"; << "READ CAPACITY(10) must fail because drive is not ready";
// READ CAPACITY(16), not READ LONG(16) // 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
<< "READ CAPACITY(16) must fail because drive is not ready"; << "READ CAPACITY(16) must fail because drive is not ready";
controller.ctrl.cmd[1] = 0x00; cmd[1] = 0x00;
disk.SetReady(true); disk.SetReady(true);
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
<< "READ CAPACITY(10) must fail because the medium has no capacity"; << "READ CAPACITY(10) must fail because the medium has no capacity";
// READ CAPACITY(16), not READ LONG(16) // 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
<< "READ CAPACITY(16) must fail because the medium has no capacity"; << "READ CAPACITY(16) must fail because the medium has no capacity";
controller.ctrl.cmd[1] = 0x00; cmd[1] = 0x00;
disk.SetBlockCount(0x12345678); disk.SetBlockCount(0x12345678);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10));
EXPECT_EQ(0x12, controller.ctrl.buffer[0]); EXPECT_EQ(0x12, controller.GetBuffer()[0]);
EXPECT_EQ(0x34, controller.ctrl.buffer[1]); EXPECT_EQ(0x34, controller.GetBuffer()[1]);
EXPECT_EQ(0x56, controller.ctrl.buffer[2]); EXPECT_EQ(0x56, controller.GetBuffer()[2]);
EXPECT_EQ(0x77, controller.ctrl.buffer[3]); EXPECT_EQ(0x77, controller.GetBuffer()[3]);
disk.SetBlockCount(0x1234567887654321); disk.SetBlockCount(0x1234567887654321);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity10));
EXPECT_EQ(0xff, controller.ctrl.buffer[0]); EXPECT_EQ(0xff, controller.GetBuffer()[0]);
EXPECT_EQ(0xff, controller.ctrl.buffer[1]); EXPECT_EQ(0xff, controller.GetBuffer()[1]);
EXPECT_EQ(0xff, controller.ctrl.buffer[2]); EXPECT_EQ(0xff, controller.GetBuffer()[2]);
EXPECT_EQ(0xff, controller.ctrl.buffer[3]); EXPECT_EQ(0xff, controller.GetBuffer()[3]);
disk.SetSectorSizeInBytes(1024); disk.SetSectorSizeInBytes(1024);
// READ CAPACITY(16), not READ LONG(16) // READ CAPACITY(16), not READ LONG(16)
controller.ctrl.cmd[1] = 0x10; cmd[1] = 0x10;
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16));
EXPECT_EQ(0x12, controller.ctrl.buffer[0]); EXPECT_EQ(0x12, controller.GetBuffer()[0]);
EXPECT_EQ(0x34, controller.ctrl.buffer[1]); EXPECT_EQ(0x34, controller.GetBuffer()[1]);
EXPECT_EQ(0x56, controller.ctrl.buffer[2]); EXPECT_EQ(0x56, controller.GetBuffer()[2]);
EXPECT_EQ(0x78, controller.ctrl.buffer[3]); EXPECT_EQ(0x78, controller.GetBuffer()[3]);
EXPECT_EQ(0x87, controller.ctrl.buffer[4]); EXPECT_EQ(0x87, controller.GetBuffer()[4]);
EXPECT_EQ(0x65, controller.ctrl.buffer[5]); EXPECT_EQ(0x65, controller.GetBuffer()[5]);
EXPECT_EQ(0x43, controller.ctrl.buffer[6]); EXPECT_EQ(0x43, controller.GetBuffer()[6]);
EXPECT_EQ(0x20, controller.ctrl.buffer[7]); EXPECT_EQ(0x20, controller.GetBuffer()[7]);
EXPECT_EQ(0x00, controller.ctrl.buffer[8]); EXPECT_EQ(0x00, controller.GetBuffer()[8]);
EXPECT_EQ(0x00, controller.ctrl.buffer[9]); EXPECT_EQ(0x00, controller.GetBuffer()[9]);
EXPECT_EQ(0x04, controller.ctrl.buffer[10]); EXPECT_EQ(0x04, controller.GetBuffer()[10]);
EXPECT_EQ(0x00, controller.ctrl.buffer[11]); EXPECT_EQ(0x00, controller.GetBuffer()[11]);
} }
TEST(DiskTest, ReadWriteLong) TEST(DiskTest, ReadWriteLong)
@ -173,51 +173,51 @@ TEST(DiskTest, ReadWriteLong)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(16); vector<int>& cmd = controller.InitCmd(16);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadLong10)); 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_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdWriteLong10)); 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
<< "READ LONG(10) must fail because the capacity is exceeded"; << "READ LONG(10) must fail because the capacity is exceeded";
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
<< "WRITE LONG(10) must fail because the capacity is exceeded"; << "WRITE LONG(10) must fail because the capacity is exceeded";
// READ LONG(16), not READ CAPACITY(16) // 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
<< "READ LONG(16) must fail because the capacity is exceeded"; << "READ LONG(16) must fail because the capacity is exceeded";
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
<< "WRITE LONG(16) must fail because the capacity is exceeded"; << "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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
<< "READ LONG(10) must fail because it currently only supports 0 bytes transfer length"; << "READ LONG(10) must fail because it currently only supports 0 bytes transfer length";
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
<< "WRITE LONG(10) must fail because it currently only supports 0 bytes transfer length"; << "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) // READ LONG(16), not READ CAPACITY(16)
controller.ctrl.cmd[1] = 0x11; cmd[1] = 0x11;
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
controller.ctrl.cmd[1] = 0x00; cmd[1] = 0x00;
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdWriteLong16)); 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) // 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) 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"; << "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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
<< "WRITE LONG(16) must fail because it currently only supports 0 bytes transfer length"; << "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.AddDevice(&disk);
controller.ctrl.cmd.resize(6); controller.InitCmd(6);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReserve6)); 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_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRelease6)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRelease6));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, SendDiagnostic) TEST(DiskTest, SendDiagnostic)
@ -247,22 +247,22 @@ TEST(DiskTest, SendDiagnostic)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(6); vector<int>& cmd = controller.InitCmd(6);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSendDiag)); 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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
<< "SEND DIAGNOSTIC must fail because PF bit is not supported"; << "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) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
<< "SEND DIAGNOSTIC must fail because parameter list is not supported"; << "SEND DIAGNOSTIC must fail because parameter list is not supported";
controller.ctrl.cmd[3] = 0; cmd[3] = 0;
controller.ctrl.cmd[4] = 1; cmd[4] = 1;
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
<< "SEND DIAGNOSTIC must fail because parameter list is not supported"; << "SEND DIAGNOSTIC must fail because parameter list is not supported";
} }
@ -274,7 +274,7 @@ TEST(DiskTest, PreventAllowMediumRemoval)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(6); vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(disk.Dispatch(scsi_command::eCmdRemoval), scsi_error_exception) EXPECT_THROW(disk.Dispatch(scsi_command::eCmdRemoval), scsi_error_exception)
<< "REMOVAL must fail because drive is not ready"; << "REMOVAL must fail because drive is not ready";
@ -283,13 +283,13 @@ TEST(DiskTest, PreventAllowMediumRemoval)
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
EXPECT_FALSE(disk.IsLocked()); EXPECT_FALSE(disk.IsLocked());
controller.ctrl.cmd[4] = 1; cmd[4] = 1;
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdRemoval));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
EXPECT_TRUE(disk.IsLocked()); EXPECT_TRUE(disk.IsLocked());
} }
@ -300,19 +300,19 @@ TEST(DiskTest, SynchronizeCache)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(10); controller.InitCmd(10);
EXPECT_CALL(disk, FlushCache()).Times(1); EXPECT_CALL(disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSynchronizeCache10)); 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(disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSynchronizeCache16)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdSynchronizeCache16));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, ReadDefectData) TEST(DiskTest, ReadDefectData)
@ -322,11 +322,11 @@ TEST(DiskTest, ReadDefectData)
controller.AddDevice(&disk); controller.AddDevice(&disk);
controller.ctrl.cmd.resize(10); controller.InitCmd(10);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadDefectData10)); EXPECT_TRUE(disk.Dispatch(scsi_command::eCmdReadDefectData10));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(DiskTest, SectorSize) TEST(DiskTest, SectorSize)

View File

@ -27,11 +27,11 @@ TEST(ModePagesTest, ModePageDevice_AddModePages)
MockModePageDevice device; MockModePageDevice device;
cdb[2] = 0x3f; cdb[2] = 0x3f;
EXPECT_EQ(0, device.AddModePages(cdb, buf.data(), 0)) << "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.data(), 1)) << "Allocation length was not limited"; EXPECT_EQ(1, device.AddModePages(cdb, buf, 0, 1)) << "Allocation length was not limited";
cdb[2] = 0x00; 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) TEST(ModePagesTest, SCSIHD_SetUpModePages)
@ -83,9 +83,8 @@ TEST(ModePagesTest, SCSICD_SetUpModePages)
TEST(ModePagesTest, SCSIMO_SetUpModePages) TEST(ModePagesTest, SCSIMO_SetUpModePages)
{ {
map<int, vector<byte>> mode_pages; map<int, vector<byte>> mode_pages;
unordered_map<uint64_t, Geometry> geometries;
const unordered_set<uint32_t> sector_sizes; const unordered_set<uint32_t> sector_sizes;
MockSCSIMO device(sector_sizes, geometries); MockSCSIMO device(sector_sizes);
device.SetUpModePages(mode_pages, 0x3f, false); device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(6, mode_pages.size()) << "Unexpected number of mode pages"; EXPECT_EQ(6, mode_pages.size()) << "Unexpected number of mode pages";
@ -117,7 +116,7 @@ TEST(ModePagesTest, ModeSelect)
// PF (vendor-specific parameter format) // PF (vendor-specific parameter format)
cdb[1] = 0x00; 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"; << "Vendor-specific parameters are not supported";
// PF (standard parameter format) // PF (standard parameter format)
@ -126,20 +125,20 @@ TEST(ModePagesTest, ModeSelect)
buf[9] = 0x00; buf[9] = 0x00;
buf[10] = 0x02; buf[10] = 0x02;
buf[11] = 0x00; 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"; << "Requested sector size does not match current sector size";
// Page 0 // Page 0
buf[LENGTH] = 0x00; 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"; << "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page) // Page 3 (Format Device Page)
buf[LENGTH] = 0x03; 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"; << "Requested sector size does not match current sector size";
// Match the requested to the current sector size // Match the requested to the current sector size
buf[LENGTH + 12] = 0x02; buf[LENGTH + 12] = 0x02;
scsi_command_util::ModeSelect(cdb, buf.data(), LENGTH + 2, 512); scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512);
} }

View File

@ -63,7 +63,7 @@ TEST(PrimaryDeviceTest, TestUnitReady)
device.SetReady(true); device.SetReady(true);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdTestUnitReady)); EXPECT_TRUE(device.Dispatch(scsi_command::eCmdTestUnitReady));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(PrimaryDeviceTest, Inquiry) TEST(PrimaryDeviceTest, Inquiry)
@ -73,9 +73,9 @@ TEST(PrimaryDeviceTest, Inquiry)
device.SetController(&controller); device.SetController(&controller);
controller.ctrl.cmd.resize(6); vector<int>& cmd = controller.InitCmd(6);
// ALLOCATION LENGTH // ALLOCATION LENGTH
controller.ctrl.cmd[4] = 255; cmd[4] = 255;
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() { ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
return device.HandleInquiry(device_type::PROCESSOR, scsi_level::SPC_3, false); 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(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry)); 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_TRUE(controller.AddDevice(&device));
EXPECT_FALSE(controller.AddDevice(&device)) << "Duplicate LUN was not rejected"; EXPECT_FALSE(controller.AddDevice(&device)) << "Duplicate LUN was not rejected";
EXPECT_CALL(device, InquiryInternal()).Times(1); EXPECT_CALL(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry)); EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
EXPECT_EQ(device_type::PROCESSOR, (device_type)controller.ctrl.buffer[0]); EXPECT_EQ(device_type::PROCESSOR, (device_type)controller.GetBuffer()[0]);
EXPECT_EQ(0x00, controller.ctrl.buffer[1]) << "Device was not reported as non-removable"; EXPECT_EQ(0x00, controller.GetBuffer()[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::SPC_3, (scsi_level)controller.GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level"; EXPECT_EQ(scsi_level::SCSI_2, (scsi_level)controller.GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size"; EXPECT_EQ(0x1f, controller.GetBuffer()[4]) << "Wrong additional data size";
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() { ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
return device.HandleInquiry(device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, true); 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(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry)); EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller.ctrl.buffer[0]); EXPECT_EQ(device_type::DIRECT_ACCESS, (device_type)controller.GetBuffer()[0]);
EXPECT_EQ(0x80, controller.ctrl.buffer[1]) << "Device was not reported as removable"; EXPECT_EQ(0x80, controller.GetBuffer()[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.GetBuffer()[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.ctrl.buffer[3]) << "Wrong response level"; EXPECT_EQ(scsi_level::SCSI_1_CCS, (scsi_level)controller.GetBuffer()[3]) << "Wrong response level";
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size"; 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_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported"; 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_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported"; EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
controller.ctrl.cmd[1] = 0x00; cmd[1] = 0x00;
controller.ctrl.cmd[2] = 0x00; cmd[2] = 0x00;
// ALLOCATION LENGTH // ALLOCATION LENGTH
controller.ctrl.cmd[4] = 1; cmd[4] = 1;
EXPECT_CALL(device, InquiryInternal()).Times(1); EXPECT_CALL(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry)); EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
EXPECT_EQ(0x1F, controller.ctrl.buffer[4]) << "Wrong additional data size"; EXPECT_EQ(0x1F, controller.GetBuffer()[4]) << "Wrong additional data size";
EXPECT_EQ(1, controller.ctrl.length) << "Wrong ALLOCATION LENGTH handling"; EXPECT_EQ(1, controller.GetLength()) << "Wrong ALLOCATION LENGTH handling";
} }
TEST(PrimaryDeviceTest, RequestSense) TEST(PrimaryDeviceTest, RequestSense)
@ -134,9 +134,9 @@ TEST(PrimaryDeviceTest, RequestSense)
controller.AddDevice(&device); controller.AddDevice(&device);
controller.ctrl.cmd.resize(6); vector<int>& cmd = controller.InitCmd(6);
// ALLOCATION LENGTH // ALLOCATION LENGTH
controller.ctrl.cmd[4] = 255; cmd[4] = 255;
device.SetReady(false); device.SetReady(false);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception); EXPECT_THROW(device.Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
@ -144,7 +144,7 @@ TEST(PrimaryDeviceTest, RequestSense)
device.SetReady(true); device.SetReady(true);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdRequestSense)); EXPECT_TRUE(device.Dispatch(scsi_command::eCmdRequestSense));
EXPECT_EQ(0, controller.ctrl.status); EXPECT_EQ(0, controller.GetStatus());
} }
TEST(PrimaryDeviceTest, ReportLuns) TEST(PrimaryDeviceTest, ReportLuns)
@ -163,13 +163,13 @@ TEST(PrimaryDeviceTest, ReportLuns)
controller.AddDevice(&device2); controller.AddDevice(&device2);
EXPECT_TRUE(controller.HasDeviceForLun(LUN2)); EXPECT_TRUE(controller.HasDeviceForLun(LUN2));
controller.ctrl.cmd.resize(10); vector<int>& cmd = controller.InitCmd(10);
// ALLOCATION LENGTH // ALLOCATION LENGTH
controller.ctrl.cmd[9] = 255; cmd[9] = 255;
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device1.Dispatch(scsi_command::eCmdReportLuns)); 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[0]) << "Wrong data length";
EXPECT_EQ(0x00, buffer[1]) << "Wrong data length"; EXPECT_EQ(0x00, buffer[1]) << "Wrong data length";
EXPECT_EQ(0x00, buffer[2]) << "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(0x00, buffer[22]) << "Wrong LUN2 number";
EXPECT_EQ(LUN2, buffer[23]) << "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"; 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.AddDevice(&device);
controller.ctrl.cmd.resize(1); controller.InitCmd(1);
EXPECT_FALSE(device.Dispatch((scsi_command)0xFF)); EXPECT_FALSE(device.Dispatch((scsi_command)0xFF));
} }

View File

@ -52,6 +52,12 @@ TEST(ScsiCommandUtilTest, GetInt16)
EXPECT_EQ(0x1234, GetInt16(v, 0)); EXPECT_EQ(0x1234, GetInt16(v, 0));
} }
TEST(ScsiCommandUtilTest, GetInt24)
{
vector<int> v = { 0x12, 0x34, 0x56 };
EXPECT_EQ(0x123456, GetInt24(v, 0));
}
TEST(ScsiCommandUtilTest, GetInt32) TEST(ScsiCommandUtilTest, GetInt32)
{ {
vector<int> v = { 0x12, 0x34, 0x56, 0x78 }; vector<int> v = { 0x12, 0x34, 0x56, 0x78 };
@ -66,11 +72,6 @@ TEST(ScsiCommandUtilTest, GetInt64)
TEST(ScsiCommandUtilTest, SetInt16) 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); vector<byte> v(2);
SetInt16(v, 0, 0x1234); SetInt16(v, 0, 0x1234);
EXPECT_EQ(byte{0x12}, v[0]); EXPECT_EQ(byte{0x12}, v[0]);
@ -80,7 +81,7 @@ TEST(ScsiCommandUtilTest, SetInt16)
TEST(ScsiCommandUtilTest, SetInt32) TEST(ScsiCommandUtilTest, SetInt32)
{ {
vector<BYTE> buf(4); vector<BYTE> buf(4);
SetInt32(buf.data(), 0x12345678); SetInt32(buf, 0, 0x12345678);
EXPECT_EQ(0x12, buf[0]); EXPECT_EQ(0x12, buf[0]);
EXPECT_EQ(0x34, buf[1]); EXPECT_EQ(0x34, buf[1]);
EXPECT_EQ(0x56, buf[2]); EXPECT_EQ(0x56, buf[2]);
@ -97,7 +98,7 @@ TEST(ScsiCommandUtilTest, SetInt32)
TEST(ScsiCommandUtilTest, SetInt64) TEST(ScsiCommandUtilTest, SetInt64)
{ {
vector<BYTE> buf(8); vector<BYTE> buf(8);
SetInt64(buf.data(), 0x1234567887654321); SetInt64(buf, 0, 0x1234567887654321);
EXPECT_EQ(0x12, buf[0]); EXPECT_EQ(0x12, buf[0]);
EXPECT_EQ(0x34, buf[1]); EXPECT_EQ(0x34, buf[1]);
EXPECT_EQ(0x56, buf[2]); EXPECT_EQ(0x56, buf[2]);

View File

@ -10,14 +10,6 @@
#include "testing.h" #include "testing.h"
#include "controllers/scsi_controller.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) TEST(ScsiControllerTest, GetMaxLuns)
{ {
MockScsiController controller(nullptr, 0); MockScsiController controller(nullptr, 0);

View File

@ -20,16 +20,23 @@
#include "devices/scsimo.h" #include "devices/scsimo.h"
#include "devices/host_services.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: public:
MOCK_METHOD(BUS::phase_t, Process, (int), (override)); MOCK_METHOD(BUS::phase_t, Process, (int), (override));
MOCK_METHOD(int, GetEffectiveLun, (), (const override)); MOCK_METHOD(int, GetEffectiveLun, (), (const override));
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override)); MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
MOCK_METHOD(int, GetInitiatorId, (), (const 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, Status, (), ());
MOCK_METHOD(void, DataIn, (), ()); MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ()); MOCK_METHOD(void, DataOut, (), ());
@ -38,60 +45,15 @@ public:
MOCK_METHOD(void, Command, (), ()); MOCK_METHOD(void, Command, (), ());
MOCK_METHOD(void, MsgIn, (), ()); MOCK_METHOD(void, MsgIn, (), ());
MOCK_METHOD(void, MsgOut, (), ()); 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, SetByteTransfer, (bool), (override));
MOCK_METHOD(void, ScheduleShutdown, (rascsi_shutdown_mode), (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); explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id, 32) {}
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
FRIEND_TEST(AbstractControllerTest, GetOpcode);
FRIEND_TEST(AbstractControllerTest, GetLun);
explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id) {}
~MockAbstractController() override = default; ~MockAbstractController() override = default;
int GetMaxLuns() const override { return 32; }
}; };
class MockScsiController final : public ScsiController 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, TestUnitReady);
FRIEND_TEST(PrimaryDeviceTest, Inquiry); FRIEND_TEST(PrimaryDeviceTest, Inquiry);
FRIEND_TEST(PrimaryDeviceTest, RequestSense); FRIEND_TEST(PrimaryDeviceTest, RequestSense);
@ -109,6 +71,12 @@ public:
FRIEND_TEST(DiskTest, SynchronizeCache); FRIEND_TEST(DiskTest, SynchronizeCache);
FRIEND_TEST(DiskTest, ReadDefectData); FRIEND_TEST(DiskTest, ReadDefectData);
public:
MOCK_METHOD(void, Status, (), ());
MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ());
using ScsiController::ScsiController; using ScsiController::ScsiController;
}; };
@ -131,14 +99,12 @@ class MockModePageDevice final : public ModePageDevice
{ {
FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages); FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages);
public:
MockModePageDevice() : ModePageDevice("test") {} MockModePageDevice() : ModePageDevice("test") {}
~MockModePageDevice() override = default; ~MockModePageDevice() override = default;
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const)); MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (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>&, 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 { void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
// Return dummy data for other pages than page 0 // 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)); MOCK_METHOD(void, FlushCache, (), (override));
MockSCSIHD_NEC() = default; using SCSIHD_NEC::SCSIHD_NEC;
~MockSCSIHD_NEC() override = default;
}; };
class MockSCSICD final : public SCSICD class MockSCSICD final : public SCSICD
{ {
FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages); FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages);
explicit MockSCSICD(const unordered_set<uint32_t>& sector_sizes) : SCSICD(sector_sizes) {} using SCSICD::SCSICD;
~MockSCSICD() override = default;
}; };
class MockSCSIMO final : public SCSIMO class MockSCSIMO final : public SCSIMO
{ {
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages); FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages);
MockSCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries) using SCSIMO::SCSIMO;
: SCSIMO(sector_sizes, geometries) {}
~MockSCSIMO() override = default;
}; };
class MockHostServices final : public HostServices class MockHostServices final : public HostServices