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

View File

@ -28,26 +28,27 @@ void command_util::ParseParameters(PbDeviceDefinition& device, const string& par
return;
}
if (params.find(KEY_VALUE_SEPARATOR) != string::npos) {
stringstream ss(params);
string p;
while (getline(ss, p, COMPONENT_SEPARATOR)) {
if (!p.empty()) {
size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
if (separator_pos != string::npos) {
AddParam(device, p.substr(0, separator_pos), string_view(p).substr(separator_pos + 1));
}
}
}
}
// Old style parameters, for backwards compatibility only.
// Only one of these parameters will be used by rascsi, depending on the device type.
else {
if (params.find(KEY_VALUE_SEPARATOR) == string::npos) {
AddParam(device, "file", params);
if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") {
AddParam(device, "interfaces", params);
}
}
return;
}
stringstream ss(params);
string p;
while (getline(ss, p, COMPONENT_SEPARATOR)) {
if (!p.empty()) {
size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
if (separator_pos != string::npos) {
AddParam(device, p.substr(0, separator_pos), string_view(p).substr(separator_pos + 1));
}
}
}
}
string command_util::GetParam(const PbCommand& command, const string& key)
@ -86,24 +87,24 @@ void command_util::AddParam(PbDeviceDefinition& device, const string& key, strin
}
}
bool command_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
const string& arg1, const string& arg2, const string& arg3)
{
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
}
bool command_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
const PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
{
// For the logfile always use English
LOGERROR("%s", context.localizer->Localize(key, "en", arg1, arg2, arg3).c_str())
LOGERROR("%s", context.localizer.Localize(key, "en", arg1, arg2, arg3).c_str())
return ReturnStatus(context, false, context.localizer->Localize(key, context.locale, arg1, arg2, arg3), error_code,
return ReturnStatus(context, false, context.localizer.Localize(key, context.locale, arg1, arg2, arg3), error_code,
false);
}
bool command_util::ReturnStatus(const CommandContext& context, bool status, const string& msg,
const PbErrorCode error_code, bool log)
PbErrorCode error_code, bool log)
{
// Do not log twice if logging has already been done in the localized error handling above
if (log && !status && !msg.empty()) {
@ -128,7 +129,7 @@ bool command_util::ReturnStatus(const CommandContext& context, bool status, cons
result.set_status(status);
result.set_error_code(error_code);
result.set_msg(msg);
context.connector->SerializeMessage(context.fd, result);
context.connector.SerializeMessage(context.fd, result);
}
return status;

View File

@ -27,10 +27,10 @@ namespace command_util
void AddParam(PbCommand&, const string&, string_view);
void AddParam(PbDevice&, const string&, string_view);
void AddParam(PbDeviceDefinition&, const string&, string_view);
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const string& = "", const string& = "",
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, const string& = "", const string& = "",
const string& = "");
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "",
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, PbErrorCode, const string& = "",
const string& = "", const string& = "");
bool ReturnStatus(const CommandContext&, bool = true, const string& = "",
const PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
}

View File

@ -10,9 +10,74 @@
#include "abstract_controller.h"
#include "devices/primary_device.h"
void AbstractController::AllocateBuffer(size_t size)
{
if (size > ctrl.buffer.size()) {
ctrl.buffer.resize(size);
}
}
PrimaryDevice *AbstractController::GetDeviceForLun(int lun) const {
const auto& it = ctrl.luns.find(lun);
return it == ctrl.luns.end() ? nullptr : it->second;
const auto& it = luns.find(lun);
return it == luns.end() ? nullptr : it->second;
}
void AbstractController::Reset()
{
SetPhase(BUS::phase_t::busfree);
ctrl.status = 0x00;
ctrl.message = 0x00;
ctrl.blocks = 0;
ctrl.next = 0;
ctrl.offset = 0;
ctrl.length = 0;
// Reset all LUNs
for (const auto& [lun, device] : luns) {
device->Reset();
}
}
void AbstractController::ProcessPhase()
{
switch (GetPhase()) {
case BUS::phase_t::busfree:
BusFree();
break;
case BUS::phase_t::selection:
Selection();
break;
case BUS::phase_t::dataout:
DataOut();
break;
case BUS::phase_t::datain:
DataIn();
break;
case BUS::phase_t::command:
Command();
break;
case BUS::phase_t::status:
Status();
break;
case BUS::phase_t::msgout:
MsgOut();
break;
case BUS::phase_t::msgin:
MsgIn();
break;
default:
assert(false);
break;
}
}
bool AbstractController::AddDevice(PrimaryDevice *device)
@ -25,7 +90,7 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
return false;
}
ctrl.luns[device->GetLun()] = device;
luns[device->GetLun()] = device;
device->SetController(this);
return true;
@ -33,12 +98,12 @@ bool AbstractController::AddDevice(PrimaryDevice *device)
bool AbstractController::DeleteDevice(const PrimaryDevice *device)
{
return ctrl.luns.erase(device->GetLun()) == 1;
return luns.erase(device->GetLun()) == 1;
}
bool AbstractController::HasDeviceForLun(int lun) const
{
return ctrl.luns.find(lun) != ctrl.luns.end();
return luns.find(lun) != luns.end();
}
int AbstractController::ExtractInitiatorId(int id_data) const

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,15 +34,6 @@ DeviceFactory::DeviceFactory()
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
sector_sizes[SCCD] = { 512, 2048};
// 128 MB, 512 bytes per sector, 248826 sectors
geometries[SCMO][0x797f400] = make_pair(512, 248826);
// 230 MB, 512 bytes per block, 446325 sectors
geometries[SCMO][0xd9eea00] = make_pair(512, 446325);
// 540 MB, 512 bytes per sector, 1041500 sectors
geometries[SCMO][0x1fc8b800] = make_pair(512, 1041500);
// 640 MB, 20248 bytes per sector, 310352 sectors
geometries[SCMO][0x25e28000] = make_pair(2048, 310352);
string network_interfaces;
for (const auto& network_interface : GetNetworkInterfaces()) {
if (!network_interfaces.empty()) {
@ -180,7 +171,7 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
break;
case SCMO:
device = make_unique<SCSIMO>(sector_sizes[SCMO], geometries[SCMO]);
device = make_unique<SCSIMO>(sector_sizes[SCMO]);
device->SetProtectable(true);
device->SetStoppable(true);
device->SetRemovable(true);
@ -232,17 +223,17 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
break;
}
assert(device != nullptr);
if (device != nullptr) {
PrimaryDevice *d = device.release();
PrimaryDevice *d = device.release();
if (d != nullptr) {
d->SetId(id);
devices.emplace(id, d);
return d;
}
return d;
return nullptr;
}
const unordered_set<uint32_t>& DeviceFactory::GetSectorSizes(PbDeviceType type) const

View File

@ -21,8 +21,6 @@
using namespace std; //NOSONAR Not relevant for rascsi
using namespace rascsi_interface; //NOSONAR Not relevant for rascsi
using Geometry = pair<uint32_t, uint32_t>;
class PrimaryDevice;
class DeviceFactory
@ -50,9 +48,6 @@ private:
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
// Optional mapping of drive capacities to drive geometries
unordered_map<PbDeviceType, unordered_map<uint64_t, Geometry>> geometries;
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
unordered_map<string, PbDeviceType> extension_mapping;

View File

@ -60,20 +60,18 @@ Disk::Disk(const string& id) : ModePageDevice(id)
Disk::~Disk()
{
// Save disk cache, only if ready
if (IsReady() && disk.dcache) {
disk.dcache->Save();
if (IsReady() && cache != nullptr) {
cache->Save();
}
delete disk.dcache;
}
bool Disk::Dispatch(scsi_command cmd)
{
// Media changes must be reported on the next access, i.e. not only for TEST UNIT READY
if (disk.is_medium_changed) {
if (is_medium_changed) {
assert(IsRemovable());
disk.is_medium_changed = false;
is_medium_changed = false;
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
}
@ -90,14 +88,10 @@ bool Disk::Dispatch(scsi_command cmd)
//---------------------------------------------------------------------------
void Disk::Open(const Filepath& path)
{
assert(disk.blocks > 0);
assert(blocks > 0);
SetReady(true);
// Cache initialization
assert (!disk.dcache);
disk.dcache = new DiskCache(path, disk.size, (uint32_t)disk.blocks, disk.image_offset);
// Can read/write open
if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) {
// Write permission
@ -114,10 +108,16 @@ void Disk::Open(const Filepath& path)
SetLocked(false);
}
void Disk::SetUpCache(const Filepath& path, off_t image_offset)
{
assert(cache == nullptr);
cache = make_unique<DiskCache>(path, size_shift_count, (uint32_t)blocks, image_offset);
}
void Disk::FlushCache()
{
if (disk.dcache) {
disk.dcache->Save();
if (cache != nullptr) {
cache->Save();
}
}
@ -146,8 +146,8 @@ void Disk::ReassignBlocks()
void Disk::Read(access_mode mode)
{
if (uint64_t start; CheckAndGetStartAndCount(start, ctrl->blocks, mode)) {
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, controller->GetLength())
// Set next block
ctrl->next = start + 1;
@ -177,7 +177,7 @@ void Disk::Read16()
void Disk::ReadWriteLong10()
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (ctrl->cmd[7] || ctrl->cmd[8]) {
if (GetInt16(ctrl->cmd, 7) != 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
@ -189,7 +189,7 @@ void Disk::ReadWriteLong10()
void Disk::ReadWriteLong16()
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (ctrl->cmd[12] || ctrl->cmd[13]) {
if (GetInt16(ctrl->cmd, 12) != 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
@ -238,7 +238,7 @@ void Disk::Verify(access_mode mode)
}
// Test reading
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), start);
// Set next block
ctrl->next = start + 1;
@ -331,24 +331,22 @@ void Disk::SynchronizeCache()
void Disk::ReadDefectData10()
{
int allocation_length = GetInt16(ctrl->cmd, 7);
if (allocation_length > 4) {
allocation_length = 4;
}
size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
// The defect list is empty
memset(ctrl->buffer, 0, allocation_length);
ctrl->length = allocation_length;
fill_n(controller->GetBuffer().begin(), allocation_length, 0);
ctrl->length = (int)allocation_length;
EnterDataInPhase();
}
void Disk::MediumChanged()
{
assert(IsRemovable());
if (IsRemovable()) {
disk.is_medium_changed = true;
is_medium_changed = true;
}
else {
LOGWARN("%s Medium change requested for non-reomvable medium", __PRETTY_FUNCTION__)
}
}
@ -357,11 +355,9 @@ bool Disk::Eject(bool force)
bool status = super::Eject(force);
if (status) {
FlushCache();
delete disk.dcache;
disk.dcache = nullptr;
cache.reset();
// The image file for this drive is not in use anymore
// TODO This cast and the FileSupport class can be removed as soon as only disk-like devices inherit from Disk
if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) {
file_support->UnreserveFile();
}
@ -370,14 +366,11 @@ bool Disk::Eject(bool force)
return status;
}
int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
{
// Get length, clear buffer
auto length = cdb[4];
if (length > max_length) {
length = max_length;
}
memset(buf, 0, length);
auto length = (int)min((size_t)max_length, (size_t)cdb[4]);
fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER
if (IsProtected()) {
@ -385,7 +378,7 @@ int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
}
// Basic information
int size = 4;
int info_size = 4;
// Add block descriptor if DBD is 0
if ((cdb[1] & 0x08) == 0) {
@ -395,37 +388,34 @@ int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
// Only if ready
if (IsReady()) {
// Short LBA mode parameter block descriptor (number of blocks and block length)
SetInt32(&buf[4], (uint32_t)GetBlockCount());
SetInt32(&buf[8], GetSectorSizeInBytes());
SetInt32(buf, 4, (uint32_t)GetBlockCount());
SetInt32(buf, 8, GetSectorSizeInBytes());
}
size = 12;
info_size = 12;
}
size += super::AddModePages(cdb, &buf[size], length - size);
if (size > 255) {
info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
if (info_size > 255) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
size = length;
if (info_size > length) {
info_size = length;
}
// Final setting of mode data length
buf[0] = (BYTE)size;
buf[0] = (BYTE)info_size;
return size;
return info_size;
}
int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf, int max_length) const
{
// Get length, clear buffer
int length = GetInt16(cdb, 7);
if (length > max_length) {
length = max_length;
}
memset(buf, 0, length);
auto length = (int)min((size_t)max_length, (size_t)GetInt16(cdb, 7));
fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER
if (IsProtected()) {
@ -433,7 +423,7 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
}
// Basic Information
int size = 8;
int info_size = 8;
// Add block descriptor if DBD is 0, only if ready
if ((cdb[1] & 0x08) == 0 && IsReady()) {
@ -446,10 +436,10 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
buf[7] = 0x08;
// Short LBA mode parameter block descriptor (number of blocks and block length)
SetInt32(&buf[8], (uint32_t)disk_blocks);
SetInt32(&buf[12], disk_size);
SetInt32(buf, 8, (uint32_t)disk_blocks);
SetInt32(buf, 12, disk_size);
size = 16;
info_size = 16;
}
else {
// Mode parameter header, LONGLBA
@ -459,27 +449,27 @@ int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
buf[7] = 0x10;
// Long LBA mode parameter block descriptor (number of blocks and block length)
SetInt64(&buf[8], disk_blocks);
SetInt32(&buf[20], disk_size);
SetInt64(buf, 8, disk_blocks);
SetInt32(buf, 20, disk_size);
size = 24;
info_size = 24;
}
}
size += super::AddModePages(cdb, &buf[size], length - size);
if (size > 65535) {
info_size += super::AddModePages(cdb, buf, info_size, length - info_size);
if (info_size > 65535) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
size = length;
if (info_size > length) {
info_size = length;
}
// Final setting of mode data length
SetInt16(buf, size);
SetInt16(buf, 0, info_size);
return size;
return info_size;
}
void Disk::SetUpModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
@ -536,7 +526,7 @@ void Disk::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
SetInt16(buf, 0x0a, 25);
// Set the number of bytes in the physical sector
SetInt16(buf, 0x0c, 1 << disk.size);
SetInt16(buf, 0x0c, 1 << size_shift_count);
// Interleave 1
SetInt16(buf, 0x0e, 1);
@ -570,7 +560,7 @@ void Disk::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
if (IsReady()) {
// Set the number of cylinders (total number of blocks
// divided by 25 sectors/track and 8 heads)
uint64_t cylinders = disk.blocks;
uint64_t cylinders = blocks;
cylinders >>= 3;
cylinders /= 25;
SetInt32(buf, 0x01, (uint32_t)cylinders);
@ -616,24 +606,24 @@ void Disk::AddVendorPage(map<int, vector<byte>>&, int, bool) const
}
// TODO Read more than one block in a single call. Currently blocked by the the track-oriented cache
int Disk::Read(const vector<int>&, BYTE *buf, uint64_t block)
int Disk::Read(const vector<int>&, vector<BYTE>& buf, uint64_t block)
{
LOGTRACE("%s", __PRETTY_FUNCTION__)
CheckReady();
// Error if the total number of blocks is exceeded
if (block >= disk.blocks) {
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// leave it to the cache
if (!disk.dcache->ReadSector(buf, (uint32_t)block)) {
if (!cache->ReadSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
}
// Success
return 1 << disk.size;
return 1 << size_shift_count;
}
int Disk::WriteCheck(uint64_t block)
@ -641,7 +631,7 @@ int Disk::WriteCheck(uint64_t block)
CheckReady();
// Error if the total number of blocks is exceeded
if (block >= disk.blocks) {
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
@ -651,11 +641,11 @@ int Disk::WriteCheck(uint64_t block)
}
// Success
return 1 << disk.size;
return 1 << size_shift_count;
}
// TODO Write more than one block in a single call. Currently blocked by the track-oriented cache
void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
{
LOGTRACE("%s", __PRETTY_FUNCTION__)
@ -665,7 +655,7 @@ void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
}
// Error if the total number of blocks is exceeded
if (block >= disk.blocks) {
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
}
@ -675,7 +665,7 @@ void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
}
// Leave it to the cache
if (!disk.dcache->WriteSector(buf, (uint32_t)block)) {
if (!cache->WriteSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
}
}
@ -709,23 +699,23 @@ void Disk::ReadCapacity10()
{
CheckReady();
if (disk.blocks == 0) {
if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
}
BYTE *buf = ctrl->buffer;
vector<BYTE>& buf = controller->GetBuffer();
// Create end of logical block address (disk.blocks-1)
uint64_t blocks = disk.blocks - 1;
// Create end of logical block address (blocks-1)
uint64_t capacity = blocks - 1;
// If the capacity exceeds 32 bit, -1 must be returned and the client has to use READ CAPACITY(16)
if (blocks > 4294967295) {
blocks = -1;
if (capacity > 4294967295) {
capacity = -1;
}
SetInt32(&buf[0], (uint32_t)blocks);
SetInt32(buf, 0, (uint32_t)capacity);
// Create block length (1 << disk.size)
SetInt32(&buf[4], 1 << disk.size);
// Create block length (1 << size)
SetInt32(buf, 4, 1 << size_shift_count);
// the size
ctrl->length = 8;
@ -737,17 +727,17 @@ void Disk::ReadCapacity16()
{
CheckReady();
if (disk.blocks == 0) {
if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
}
BYTE *buf = ctrl->buffer;
vector<BYTE>& buf = controller->GetBuffer();
// Create end of logical block address (disk.blocks-1)
SetInt64(&buf[0], disk.blocks - 1);
// Create end of logical block address (blocks-1)
SetInt64(buf, 0, blocks - 1);
// Create block length (1 << disk.size)
SetInt32(&buf[8], 1 << disk.size);
// Create block length (1 << size)
SetInt32(buf, 8, 1 << size_shift_count);
buf[12] = 0;
@ -820,11 +810,7 @@ void Disk::ValidateBlockAddress(access_mode mode) const
bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mode mode) const
{
if (mode == RW6 || mode == SEEK6) {
start = ctrl->cmd[1] & 0x1f;
start <<= 8;
start |= ctrl->cmd[2];
start <<= 8;
start |= ctrl->cmd[3];
start = GetInt24(ctrl->cmd, 1);
count = ctrl->cmd[4];
if (!count) {
@ -864,7 +850,7 @@ bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mod
uint32_t Disk::GetSectorSizeInBytes() const
{
return disk.size ? 1 << disk.size : 0;
return size_shift_count ? 1 << size_shift_count : 0;
}
void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
@ -877,19 +863,19 @@ void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
switch (size_in_bytes) {
case 512:
disk.size = 9;
size_shift_count = 9;
break;
case 1024:
disk.size = 10;
size_shift_count = 10;
break;
case 2048:
disk.size = 11;
size_shift_count = 11;
break;
case 4096:
disk.size = 12;
size_shift_count = 12;
break;
default:
@ -898,49 +884,19 @@ void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
}
}
uint32_t Disk::GetSectorSizeShiftCount() const
{
return disk.size;
}
void Disk::SetSectorSizeShiftCount(uint32_t shift_count)
{
disk.size = shift_count;
}
bool Disk::IsSectorSizeConfigurable() const
{
return !sector_sizes.empty();
}
void Disk::SetSectorSizes(const unordered_set<uint32_t>& sizes)
{
sector_sizes = sizes;
}
uint32_t Disk::GetConfiguredSectorSize() const
{
return configured_sector_size;
}
bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t size)
bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t configured_size)
{
if (unordered_set<uint32_t> sizes = device_factory.GetSectorSizes(GetType());
sizes.find(size) == sizes.end()) {
sizes.find(configured_size) == sizes.end()) {
return false;
}
configured_sector_size = size;
configured_sector_size = configured_size;
return true;
}
uint64_t Disk::GetBlockCount() const
{
return disk.blocks;
}
void Disk::SetBlockCount(uint64_t blocks)
{
disk.blocks = blocks;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,12 +11,14 @@
#include "log.h"
#include "rascsi_exceptions.h"
#include "scsi_command_util.h"
#include "dispatcher.h"
#include "mode_page_device.h"
#include <cstddef>
using namespace std;
using namespace scsi_defs;
using namespace scsi_command_util;
ModePageDevice::ModePageDevice(const string& id) : PrimaryDevice(id)
{
@ -32,7 +34,7 @@ bool ModePageDevice::Dispatch(scsi_command cmd)
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const
int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int offset, int max_length) const
{
if (max_length < 0) {
return 0;
@ -77,36 +79,34 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_leng
// Page 0 must be last
if (!page0.empty()) {
size_t offset = result.size();
// Page data
result.insert(result.end(), page0.begin(), page0.end());
// Page payload size
result[offset + 1] = (byte)(page0.size() - 2);
result[result.size() + 1] = (byte)(page0.size() - 2);
}
// Do not return more than the requested number of bytes
size_t size = (size_t)max_length < result.size() ? max_length : result.size();
memcpy(buf, result.data(), size);
size_t size = min((size_t)max_length, result.size());
memcpy(&buf.data()[offset], result.data(), size);
return (int)size;
}
void ModePageDevice::ModeSense6()
{
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
ctrl->length = ModeSense6(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
EnterDataInPhase();
}
void ModePageDevice::ModeSense10()
{
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
ctrl->length = ModeSense10(ctrl->cmd, controller->GetBuffer(), (int)controller->GetBufferSize());
EnterDataInPhase();
}
void ModePageDevice::ModeSelect(const vector<int>&, const BYTE *, int) const
void ModePageDevice::ModeSelect(const vector<int>&, const vector<BYTE>&, int) const
{
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
}
@ -127,7 +127,7 @@ void ModePageDevice::ModeSelect10()
int ModePageDevice::ModeSelectCheck(int length) const
{
// Error if save parameters are set for other types than of SCHD, SCRM or SCMO
// Error if save parameters are set for other types than SCHD, SCRM or SCMO
// TODO The assumption above is not correct, and this code should be located elsewhere
if (GetType() != "SCHD" && GetType() != "SCRM" && GetType() != "SCMO" && (ctrl->cmd[1] & 0x01)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
@ -145,12 +145,7 @@ int ModePageDevice::ModeSelectCheck6() const
int ModePageDevice::ModeSelectCheck10() const
{
// Receive the data specified by the parameter length
int length = ctrl->cmd[7];
length <<= 8;
length |= ctrl->cmd[8];
if (length > ctrl->bufsize) {
length = ctrl->bufsize;
}
size_t length = min(controller->GetBufferSize(), (size_t)GetInt16(ctrl->cmd, 7));
return ModeSelectCheck(length);
return ModeSelectCheck((int)length);
}

View File

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

View File

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

View File

@ -30,7 +30,7 @@ public:
virtual bool Dispatch(scsi_command);
void SetController(AbstractController *);
virtual bool WriteByteSequence(BYTE *, uint32_t);
virtual bool WriteByteSequence(vector<BYTE>&, uint32_t);
virtual int GetSendDelay() const { return BUS::SEND_NO_DELAY; }
protected:

View File

@ -13,63 +13,61 @@
using namespace scsi_defs;
void scsi_command_util::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length, int sector_size)
void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& buf, int length, int sector_size)
{
assert(length >= 0);
int offset = 0;
// PF
if (cdb[1] & 0x10) {
bool has_valid_page_code = false;
if (!(cdb[1] & 0x10)) {
// Vendor-specific parameters (SCSI-1) are not supported
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
// Mode Parameter header
if (length >= 12) {
// Check the block length
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) ||
buf[11] != (BYTE)sector_size) {
// See below for details
bool has_valid_page_code = false;
// Mode Parameter header
int offset = 0;
if (length >= 12) {
// Check the block length
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) ||
buf[11] != (BYTE)sector_size) {
// See below for details
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
offset += 12;
length -= 12;
}
// Parsing the page
// TODO The length handling is wrong in case of length < size
while (length > 0) {
// Format device page
if (int page = buf[offset]; page == 0x03) {
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
// drives support this, e.g FUJITSU M2624S
// We are fine as long as the current sector size remains unchanged
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
// With rascsi it is not possible to permanently (by formatting) change the sector size,
// because the size is an externally configurable setting only
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
offset += 12;
length -= 12;
has_valid_page_code = true;
}
else {
LOGWARN("Unknown MODE SELECT page code: $%02X", page)
}
// Parsing the page
// TODO The length handling is wrong in case of length < size
while (length > 0) {
// Format device page
if (int page = buf[offset]; page == 0x03) {
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
// drives support this, e.g FUJITSU M2624S
// We are fine as long as the current sector size remains unchanged
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
// With rascsi it is not possible to permanently (by formatting) change the sector size,
// because the size is an externally configurable setting only
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
has_valid_page_code = true;
}
else {
LOGWARN("Unknown MODE SELECT page code: $%02X", page)
}
// Advance to the next page
int size = buf[offset + 1] + 2;
length -= size;
offset += size;
}
if (!has_valid_page_code) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
// Advance to the next page
int size = buf[offset + 1] + 2;
length -= size;
offset += size;
}
else {
// Vendor-specific parameters (SCSI-1) are not supported
if (!has_valid_page_code) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
}
@ -105,6 +103,11 @@ int scsi_command_util::GetInt16(const vector<int>& buf, int offset)
return (buf[offset] << 8) | buf[offset + 1];
}
int scsi_command_util::GetInt24(const vector<int>& buf, int offset)
{
return (buf[offset] << 16) | (buf[offset + 1] << 8) | buf[offset + 2];
}
uint32_t scsi_command_util::GetInt32(const vector<int>& buf, int offset)
{
return ((uint32_t)buf[offset] << 24) | ((uint32_t)buf[offset + 1] << 16) |
@ -119,42 +122,42 @@ uint64_t scsi_command_util::GetInt64(const vector<int>& buf, int offset)
((uint64_t)buf[offset + 6] << 8) | (uint64_t)buf[offset + 7];
}
void scsi_command_util::SetInt16(BYTE *buf, int value)
{
buf[0] = (BYTE)(value >> 8);
buf[1] = (BYTE)value;
}
void scsi_command_util::SetInt32(BYTE *buf, uint32_t value)
{
buf[0] = (BYTE)(value >> 24);
buf[1] = (BYTE)(value >> 16);
buf[2] = (BYTE)(value >> 8);
buf[3] = (BYTE)value;
}
void scsi_command_util::SetInt64(BYTE *buf, uint64_t value)
{
buf[0] = (BYTE)(value >> 56);
buf[1] = (BYTE)(value >> 48);
buf[2] = (BYTE)(value >> 40);
buf[3] = (BYTE)(value >> 32);
buf[4] = (BYTE)(value >> 24);
buf[5] = (BYTE)(value >> 16);
buf[6] = (BYTE)(value >> 8);
buf[7] = (BYTE)value;
}
void scsi_command_util::SetInt16(vector<byte>& buf, int offset, int value)
{
buf[offset] = (byte)(value >> 8);
buf[offset + 1] = (byte)value;
}
void scsi_command_util::SetInt32(vector<byte>& buf, int offset, int value)
void scsi_command_util::SetInt32(vector<byte>& buf, int offset, uint32_t value)
{
buf[offset] = (byte)(value >> 24);
buf[offset + 1] = (byte)(value >> 16);
buf[offset + 2] = (byte)(value >> 8);
buf[offset + 3] = (byte)value;
}
void scsi_command_util::SetInt16(vector<BYTE>& buf, int offset, int value)
{
buf[offset] = (BYTE)(value >> 8);
buf[offset + 1] = (BYTE)value;
}
void scsi_command_util::SetInt32(vector<BYTE>& buf, int offset, uint32_t value)
{
buf[offset] = (BYTE)(value >> 24);
buf[offset + 1] = (BYTE)(value >> 16);
buf[offset + 2] = (BYTE)(value >> 8);
buf[offset + 3] = (BYTE)value;
}
void scsi_command_util::SetInt64(vector<BYTE>& buf, int offset, uint64_t value)
{
buf[offset] = (BYTE)(value >> 56);
buf[offset + 1] = (BYTE)(value >> 48);
buf[offset + 2] = (BYTE)(value >> 40);
buf[offset + 3] = (BYTE)(value >> 32);
buf[offset + 4] = (BYTE)(value >> 24);
buf[offset + 5] = (BYTE)(value >> 16);
buf[offset + 6] = (BYTE)(value >> 8);
buf[offset + 7] = (BYTE)value;
}

View File

@ -18,16 +18,17 @@ using namespace std; //NOSONAR Not relevant for rascsi
namespace scsi_command_util
{
void ModeSelect(const vector<int>&, const BYTE *, int, int);
void ModeSelect(const vector<int>&, const vector<BYTE>&, int, int);
void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
int GetInt16(const vector<int>&, int);
int GetInt24(const vector<int>&, int);
uint32_t GetInt32(const vector<int>&, int);
uint64_t GetInt64(const vector<int>&, int);
void SetInt16(BYTE *, int);
void SetInt32(BYTE *, uint32_t);
void SetInt64(BYTE *, uint64_t);
void SetInt16(vector<byte>&, int, int);
void SetInt32(vector<byte>&, int, int);
void SetInt32(vector<byte>&, int, uint32_t);
void SetInt16(vector<BYTE>&, int, int);
void SetInt32(vector<BYTE>&, int, uint32_t);
void SetInt64(vector<BYTE>&, int, uint64_t);
}

View File

@ -79,20 +79,6 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
SetReady(true);
SetReset(false);
// if (m_bTapEnable) {
// tap->GetMacAddr(m_mac_addr);
// m_mac_addr[5]++;
// }
// !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development!
// TODO: Remove this hard-coded address
m_mac_addr[0] = (byte)0x00;
m_mac_addr[1] = (byte)0x80;
m_mac_addr[2] = (byte)0x19;
m_mac_addr[3] = (byte)0x10;
m_mac_addr[4] = (byte)0x98;
m_mac_addr[5] = (byte)0xE3;
return true;
}
@ -144,10 +130,10 @@ vector<byte> SCSIDaynaPort::InquiryInternal() const
// - The SCSI/Link apparently has about 6KB buffer space for packets.
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
{
int rx_packet_size = 0;
auto response = (scsi_resp_read_t*)buf;
auto response = (scsi_resp_read_t*)buf.data();
int requested_length = cdb[4];
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length)
@ -246,8 +232,8 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
// breaks because of this, the work-around has to be re-evaluated.
size = 64;
}
SetInt16(&buf[0], size);
SetInt32(&buf[2], m_tap.PendingPackets() ? 0x10 : 0x00);
SetInt16(buf, 0, size);
SetInt32(buf, 2, m_tap.PendingPackets() ? 0x10 : 0x00);
// Return the packet size + 2 for the length + 4 for the flag field
// The CRC was already appended by the ctapdriver
@ -291,19 +277,19 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
// XX XX ... is the actual packet
//
//---------------------------------------------------------------------------
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t)
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const vector<BYTE>& buf, uint64_t)
{
int data_format = cdb[5];
int data_length = cdb[4] + (cdb[3] << 8);
int data_length = GetInt16(cdb, 3);
if (data_format == 0x00){
m_tap.Send(buf, data_length);
m_tap.Send(buf.data(), data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
}
else if (data_format == 0x80){
// The data length is specified in the first 2 bytes of the payload
data_length=buf[1] + (buf[0] << 8);
m_tap.Send(&buf[4], data_length);
m_tap.Send(&(buf.data()[4]), data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
}
else
@ -331,33 +317,11 @@ bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t
// - long #3: frames lost
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, BYTE *buffer) const
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, vector<BYTE>& buf) const
{
int allocation_length = cdb[4] + (cdb[3] << 8);
memcpy(buf.data(), &m_scsi_link_stats, sizeof(m_scsi_link_stats));
// memset(buffer,0,18);
// memcpy(&buffer[0],m_mac_addr,sizeof(m_mac_addr));
// uint32_t frame_alignment_errors;
// uint32_t crc_errors;
// uint32_t frames_lost;
// // frame alignment errors
// frame_alignment_errors = htonl(0);
// memcpy(&(buffer[6]),&frame_alignment_errors,sizeof(frame_alignment_errors));
// // CRC errors
// crc_errors = htonl(0);
// memcpy(&(buffer[10]),&crc_errors,sizeof(crc_errors));
// // frames lost
// frames_lost = htonl(0);
// memcpy(&(buffer[14]),&frames_lost,sizeof(frames_lost));
int response_size = sizeof(m_scsi_link_stats);
memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats));
if (response_size > allocation_length) {
response_size = allocation_length;
}
return response_size;
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 4));
}
//---------------------------------------------------------------------------
@ -407,11 +371,7 @@ void SCSIDaynaPort::TestUnitReady()
void SCSIDaynaPort::Read6()
{
// Get record number and block number
uint32_t record = ctrl->cmd[1] & 0x1f;
record <<= 8;
record |= ctrl->cmd[2];
record <<= 8;
record |= ctrl->cmd[3];
uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
ctrl->blocks=1;
// If any commands have a bogus control value, they were probably not
@ -423,7 +383,7 @@ void SCSIDaynaPort::Read6()
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
ctrl->length = Read(ctrl->cmd, controller->GetBuffer(), record);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
// Set next block
@ -434,20 +394,16 @@ void SCSIDaynaPort::Read6()
void SCSIDaynaPort::Write6()
{
// Reallocate buffer (because it is not transfer for each block)
if (ctrl->bufsize < DAYNAPORT_BUFFER_SIZE) {
delete[] ctrl->buffer;
ctrl->buffer = new BYTE[ctrl->bufsize];
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
}
// Ensure a sufficient buffer size (because it is not transfer for each block)
controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
int data_format = ctrl->cmd[5];
if(data_format == 0x00) {
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
if (data_format == 0x00) {
ctrl->length = GetInt16(ctrl->cmd, 3);
}
else if (data_format == 0x80) {
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8) + 8;
ctrl->length = GetInt16(ctrl->cmd, 3 + 8);
}
else {
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
@ -467,7 +423,7 @@ void SCSIDaynaPort::Write6()
void SCSIDaynaPort::RetrieveStatistics()
{
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
ctrl->length = RetrieveStats(ctrl->cmd, controller->GetBuffer());
// Set next block
ctrl->blocks = 1;
@ -506,7 +462,7 @@ void SCSIDaynaPort::SetInterfaceMode()
{
// Check whether this command is telling us to "Set Interface Mode" or "Set MAC Address"
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
ctrl->length = RetrieveStats(ctrl->cmd, controller->GetBuffer());
switch(ctrl->cmd[5]){
case CMD_SCSILINK_SETMODE:
// TODO Not implemented, do nothing

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -31,13 +31,13 @@ public:
SCSIHD(SCSIHD&) = delete;
SCSIHD& operator=(const SCSIHD&) = delete;
void FinalizeSetup(const Filepath&, off_t);
void FinalizeSetup(const Filepath&, off_t, off_t = 0);
void Open(const Filepath&) override;
// Commands
vector<byte> InquiryInternal() const override;
void ModeSelect(const vector<int>&, const BYTE *, int) const override;
void ModeSelect(const vector<int>&, const vector<BYTE>&, int) const override;
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;

View File

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

View File

@ -13,9 +13,14 @@
// [ SCSI NEC "Genuine" Hard Disk]
//
//---------------------------------------------------------------------------
#pragma once
#include "scsihd.h"
#include <unordered_set>
#include <map>
using namespace std; //NOSONAR Not relevant for rascsi
//===========================================================================
//
@ -24,16 +29,14 @@
//===========================================================================
class SCSIHD_NEC : public SCSIHD
{
static const unordered_set<uint32_t> sector_sizes;
public:
explicit SCSIHD_NEC() : SCSIHD(sector_sizes, false) {}
SCSIHD_NEC() : SCSIHD(sector_sizes, false) {}
~SCSIHD_NEC() override = default;
SCSIHD_NEC(SCSIHD_NEC&) = delete;
SCSIHD_NEC& operator=(const SCSIHD_NEC&) = delete;
void Open(const Filepath& path) override;
void Open(const Filepath&) override;
vector<byte> InquiryInternal() const override;
@ -43,6 +46,11 @@ public:
private:
static const unordered_set<uint32_t> sector_sizes;
// Image file offset (NEC only)
off_t image_offset = 0;
// Geometry data
int cylinders = 0;
int heads = 0;

View File

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

View File

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

View File

@ -42,10 +42,6 @@ bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
break;
case OpenMode::ReadWrite:
// Make sure RW does not succeed when reading from CD-ROM
if (access(fname, 0x06) != 0) {
return false;
}
handle = open(fname, O_RDWR | omode);
break;
@ -115,7 +111,7 @@ off_t Fileio::GetFileSize() const
assert(handle >= 0);
// Get file position in 64bit
off_t cur = GetFilePos();
off_t cur = lseek(handle, 0, SEEK_CUR);
// Get file size in64bitで
off_t end = lseek(handle, 0, SEEK_END);
@ -126,14 +122,6 @@ off_t Fileio::GetFileSize() const
return end;
}
off_t Fileio::GetFilePos() const
{
assert(handle >= 0);
// Get file position in 64bit
return lseek(handle, 0, SEEK_CUR);
}
void Fileio::Close()
{
if (handle != -1) {

View File

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

View File

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

View File

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

View File

@ -17,155 +17,154 @@ using namespace std;
Localizer::Localizer()
{
// Positional string arguments are %1, %2, %3
Add(ERROR_AUTHENTICATION, "en", "Authentication failed");
Add(ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
Add(ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades");
Add(ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
Add(ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
Add(ERROR_OPERATION, "en", "Unknown operation");
Add(ERROR_OPERATION, "de", "Unbekannte Operation");
Add(ERROR_OPERATION, "sv", "Okänd operation");
Add(ERROR_OPERATION, "fr", "Opération inconnue");
Add(ERROR_OPERATION, "es", "Operación desconocida");
Add(ERROR_LOG_LEVEL, "en", "Invalid log level %1");
Add(ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
Add(ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
Add(ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
Add(ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
Add(ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
Add(ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
Add(ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas");
Add(ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
Add(ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
Add(ERROR_MISSING_FILENAME, "en", "Missing filename");
Add(ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
Add(ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
Add(ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
Add(ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
Add(ERROR_DEVICE_MISSING_FILENAME, "de", "Gerätetyp %1 erfordert einen Dateinamen");
Add(ERROR_DEVICE_MISSING_FILENAME, "sv", "Enhetstypen %1 kräver ett filnamn");
Add(ERROR_DEVICE_MISSING_FILENAME, "es", "El tipo de dispositivo %1 requiere un nombre de archivo");
Add(ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
Add(ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
Add(ERROR_IMAGE_IN_USE, "sv", "Skivbildsfilen '%1' används redan av id %2, enhetsnummer %3");
Add(ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
Add(ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
Add(ERROR_IMAGE_FILE_INFO, "en", "Can't create image file info for '%1'");
Add(ERROR_IMAGE_FILE_INFO, "de", "Image-Datei-Information für '%1' kann nicht erzeugt werden");
Add(ERROR_IMAGE_FILE_INFO, "sv", "Kunde ej skapa skivbildsfilsinfo för '%1'");
Add(ERROR_IMAGE_FILE_INFO, "es", "No se puede crear información de archivo de imagen para '%1'");
Add(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
Add(ERROR_RESERVED_ID, "sv", "Enhets-id %1 är reserverat");
Add(ERROR_RESERVED_ID, "fr", "ID de périphérique %1 réservée");
Add(ERROR_RESERVED_ID, "es", "El ID de dispositivo %1 está reservado");
Add(ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
Add(ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
Add(ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för id %1 som ej existerar");
Add(ERROR_NON_EXISTING_DEVICE, "fr", "Commande pour ID %1 non-existant");
Add(ERROR_NON_EXISTING_DEVICE, "es", "Comando para ID %1 no existente");
Add(ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
Add(ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
Add(ERROR_NON_EXISTING_UNIT, "sv", "Kommando för id %1, enhetsnummer %2 som ej existerar");
Add(ERROR_NON_EXISTING_UNIT, "fr", "Command pour ID %1, unité %2 non-existant");
Add(ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "es", "Tipo de dispositivo desconocido %1");
Add(ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "fr", "Type de périphérique requis pour extension inconnue du fichier '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "es", "Tipo de dispositivo requerido para la extensión desconocida del archivo '%1'");
Add(ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
Add(ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2");
Add(ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
Add(ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
Add(ERROR_DETACH, "en", "Couldn't detach device");
Add(ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
Add(ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten");
Add(ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo");
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
Add(ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
Add(ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
Add(ERROR_EJECT_REQUIRED, "fr", "Media déjà existant doit d'abord être éjecté");
Add(ERROR_EJECT_REQUIRED, "es", "El medio existente debe ser expulsado primero");
Add(ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
Add(ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
Add(ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
Add(ERROR_DEVICE_NAME_UPDATE, "fr", "Une fois défini, le nom de périphérique ne peut plus être changé");
Add(ERROR_DEVICE_NAME_UPDATE, "es", "Una vez establecido el nombre del dispositivo ya no se puede cambiar");
Add(ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
Add(ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
Add(ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
Add(ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
Add(ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
Add(ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
Add(ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
Add(ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
Add(ERROR_SHUTDOWN_PERMISSION, "sv", "Saknar root-rättigheter för att kunna stänga av eller starta om systemet");
Add(ERROR_SHUTDOWN_PERMISSION, "fr", "Permissions root manquantes pour extinction ou redémarrage");
Add(ERROR_SHUTDOWN_PERMISSION, "es", "Falta el permiso de root para el apagado o el reinicio");
Add(ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
Add(ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
Add(ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
Add(ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
Add(ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2");
Add(ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
Add(ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
Add(ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
Add(ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
Add(ERROR_BLOCK_SIZE, "es", "Tamaño de bloque inválido %1 bytes");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
Add(ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller");
Add(ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
Add(ERROR_SCSI_CONTROLLER, "sv", "Kunde ej skapa SCSI-gränssnitt");
Add(ERROR_SCSI_CONTROLLER, "es", "No se ha podido crear el controlador SCSI");
Add(ERROR_INVALID_ID, "en", "Invalid device ID %1 (0-%2)");
Add(ERROR_INVALID_ID, "de", "Ungültige Geräte-ID %1 (0-%2)");
Add(ERROR_INVALID_ID, "sv", "Ogiltigt enhets-id %1 (0-%2)");
Add(ERROR_INVALID_ID, "es", "ID de dispositivo inválido %1 (0-%2)");
Add(ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
Add(ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
Add(ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)");
Add(ERROR_INVALID_LUN, "es", "LUN invalido %1 (0-%2)");
Add(ERROR_LUN0, "en", "LUN 0 cannot be detached as long as there is still another LUN");
Add(ERROR_LUN0, "de", "LUN 0 kann nicht entfernt werden, solange noch eine andere LUN existiert");
Add(ERROR_LUN0, "sv", "Enhetsnummer 0 kan ej bli frånkopplat så länge som andra enhetsnummer är anslutna");
Add(ERROR_LUN0, "es", "El LUN 0 no se puede desconectar mientras haya otro LUN");
Add(ERROR_INITIALIZATION, "en", "Initialization of %1 device, ID %2, LUN %3 failed");
Add(ERROR_INITIALIZATION, "de", "Initialisierung von %1-Gerät, ID %2, LUN %3 fehlgeschlagen");
Add(ERROR_INITIALIZATION, "sv", "Kunde ej initialisera enheten %1 med id %2 och enhetsnummer %3");
Add(ERROR_INITIALIZATION, "es", "La inicialización del dispositivo %1, ID %2, LUN %3 falló");
Add(ERROR_OPERATION_DENIED_STOPPABLE, "en", "%1 operation denied, %2 isn't stoppable");
Add(ERROR_OPERATION_DENIED_STOPPABLE, "de", "%1-Operation verweigert, %2 ist nicht stopbar");
Add(ERROR_OPERATION_DENIED_STOPPABLE, "sv", "Operationen %1 nekades för att %2 inte kan stoppas");
Add(ERROR_OPERATION_DENIED_STOPPABLE, "es", "%1 operación denegada, %2 no se puede parar");
Add(ERROR_OPERATION_DENIED_REMOVABLE, "en", "%1 operation denied, %2 isn't removable");
Add(ERROR_OPERATION_DENIED_REMOVABLE, "de", "%1-Operation verweigert, %2 ist nicht wechselbar");
Add(ERROR_OPERATION_DENIED_REMOVABLE, "sv", "Operationen %1 nekades för att %2 inte är uttagbar(t)");
Add(ERROR_OPERATION_DENIED_REMOVABLE, "es", "%1 operación denegada, %2 no es removible");
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "en", "%1 operation denied, %2 isn't protectable");
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "de", "%1-Operation verweigert, %2 ist nicht schützbar");
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "sv", "Operationen %1 nekades för att %2 inte är skyddbar(t)");
Add(ERROR_OPERATION_DENIED_PROTECTABLE, "es", "%1 operación denegada, %2 no es protegible");
Add(ERROR_OPERATION_DENIED_READY, "en", "%1 operation denied, %2 isn't ready");
Add(ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit");
Add(ERROR_OPERATION_DENIED_READY, "sv", "Operationen %1 nekades för att %2 inte är redo");
Add(ERROR_OPERATION_DENIED_READY, "es", "%1 operación denegada, %2 no está listo");
Add(LocalizationKey::ERROR_AUTHENTICATION, "en", "Authentication failed");
Add(LocalizationKey::ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
Add(LocalizationKey::ERROR_AUTHENTICATION, "sv", "Autentiseringen misslyckades");
Add(LocalizationKey::ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
Add(LocalizationKey::ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
Add(LocalizationKey::ERROR_OPERATION, "en", "Unknown operation");
Add(LocalizationKey::ERROR_OPERATION, "de", "Unbekannte Operation");
Add(LocalizationKey::ERROR_OPERATION, "sv", "Okänd operation");
Add(LocalizationKey::ERROR_OPERATION, "fr", "Opération inconnue");
Add(LocalizationKey::ERROR_OPERATION, "es", "Operación desconocida");
Add(LocalizationKey::ERROR_LOG_LEVEL, "en", "Invalid log level %1");
Add(LocalizationKey::ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
Add(LocalizationKey::ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
Add(LocalizationKey::ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
Add(LocalizationKey::ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "sv", "Enhetens id saknas");
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
Add(LocalizationKey::ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
Add(LocalizationKey::ERROR_MISSING_FILENAME, "en", "Missing filename");
Add(LocalizationKey::ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
Add(LocalizationKey::ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
Add(LocalizationKey::ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
Add(LocalizationKey::ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "en", "Device type %1 requires a filename");
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "de", "Gerätetyp %1 erfordert einen Dateinamen");
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "sv", "Enhetstypen %1 kräver ett filnamn");
Add(LocalizationKey::ERROR_DEVICE_MISSING_FILENAME, "es", "El tipo de dispositivo %1 requiere un nombre de archivo");
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "sv", "Skivbildsfilen '%1' används redan av id %2, enhetsnummer %3");
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
Add(LocalizationKey::ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "en", "Can't create image file info for '%1'");
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "de", "Image-Datei-Information für '%1' kann nicht erzeugt werden");
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "sv", "Kunde ej skapa skivbildsfilsinfo för '%1'");
Add(LocalizationKey::ERROR_IMAGE_FILE_INFO, "es", "No se puede crear información de archivo de imagen para '%1'");
Add(LocalizationKey::ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
Add(LocalizationKey::ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
Add(LocalizationKey::ERROR_RESERVED_ID, "sv", "Enhets-id %1 är reserverat");
Add(LocalizationKey::ERROR_RESERVED_ID, "fr", "ID de périphérique %1 réservée");
Add(LocalizationKey::ERROR_RESERVED_ID, "es", "El ID de dispositivo %1 está reservado");
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för id %1 som ej existerar");
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "fr", "Commande pour ID %1 non-existant");
Add(LocalizationKey::ERROR_NON_EXISTING_DEVICE, "es", "Comando para ID %1 no existente");
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "sv", "Kommando för id %1, enhetsnummer %2 som ej existerar");
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "fr", "Command pour ID %1, unité %2 non-existant");
Add(LocalizationKey::ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2");
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
Add(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, "es", "Tipo de dispositivo desconocido %1");
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "fr", "Type de périphérique requis pour extension inconnue du fichier '%1'");
Add(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, "es", "Tipo de dispositivo requerido para la extensión desconocida del archivo '%1'");
Add(LocalizationKey::ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
Add(LocalizationKey::ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
Add(LocalizationKey::ERROR_DUPLICATE_ID, "sv", "Duplikat id %1, enhetsnummer %2");
Add(LocalizationKey::ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
Add(LocalizationKey::ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
Add(LocalizationKey::ERROR_DETACH, "en", "Couldn't detach device");
Add(LocalizationKey::ERROR_DETACH, "de", "Geräte konnte nicht entfernt werden");
Add(LocalizationKey::ERROR_DETACH, "sv", "Kunde ej koppla ifrån enheten");
Add(LocalizationKey::ERROR_DETACH, "es", "No se ha podido desconectar el dispositivo");
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "fr", "Media déjà existant doit d'abord être éjecté");
Add(LocalizationKey::ERROR_EJECT_REQUIRED, "es", "El medio existente debe ser expulsado primero");
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "fr", "Une fois défini, le nom de périphérique ne peut plus être changé");
Add(LocalizationKey::ERROR_DEVICE_NAME_UPDATE, "es", "Una vez establecido el nombre del dispositivo ya no se puede cambiar");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
Add(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "sv", "Saknar root-rättigheter för att kunna stänga av eller starta om systemet");
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "fr", "Permissions root manquantes pour extinction ou redémarrage");
Add(LocalizationKey::ERROR_SHUTDOWN_PERMISSION, "es", "Falta el permiso de root para el apagado o el reinicio");
Add(LocalizationKey::ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
Add(LocalizationKey::ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
Add(LocalizationKey::ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
Add(LocalizationKey::ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
Add(LocalizationKey::ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2");
Add(LocalizationKey::ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
Add(LocalizationKey::ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
Add(LocalizationKey::ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
Add(LocalizationKey::ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
Add(LocalizationKey::ERROR_BLOCK_SIZE, "es", "Tamaño de bloque inválido %1 bytes");
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
Add(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "en", "Couldn't create SCSI controller");
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "de", "SCSI-Controller konnte nicht erzeugt werden");
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "sv", "Kunde ej skapa SCSI-gränssnitt");
Add(LocalizationKey::ERROR_SCSI_CONTROLLER, "es", "No se ha podido crear el controlador SCSI");
Add(LocalizationKey::ERROR_INVALID_ID, "en", "Invalid device ID %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_ID, "de", "Ungültige Geräte-ID %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_ID, "sv", "Ogiltigt enhets-id %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_ID, "es", "ID de dispositivo inválido %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_LUN, "en", "Invalid LUN %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_LUN, "de", "Ungültige LUN %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_LUN, "sv", "Ogiltigt enhetsnummer %1 (0-%2)");
Add(LocalizationKey::ERROR_INVALID_LUN, "es", "LUN invalido %1 (0-%2)");
Add(LocalizationKey::ERROR_LUN0, "en", "LUN 0 cannot be detached as long as there is still another LUN");
Add(LocalizationKey::ERROR_LUN0, "de", "LUN 0 kann nicht entfernt werden, solange noch eine andere LUN existiert");
Add(LocalizationKey::ERROR_LUN0, "sv", "Enhetsnummer 0 kan ej bli frånkopplat så länge som andra enhetsnummer är anslutna");
Add(LocalizationKey::ERROR_LUN0, "es", "El LUN 0 no se puede desconectar mientras haya otro LUN");
Add(LocalizationKey::ERROR_INITIALIZATION, "en", "Initialization of %1 device, ID %2, LUN %3 failed");
Add(LocalizationKey::ERROR_INITIALIZATION, "de", "Initialisierung von %1-Gerät, ID %2, LUN %3 fehlgeschlagen");
Add(LocalizationKey::ERROR_INITIALIZATION, "sv", "Kunde ej initialisera enheten %1 med id %2 och enhetsnummer %3");
Add(LocalizationKey::ERROR_INITIALIZATION, "es", "La inicialización del dispositivo %1, ID %2, LUN %3 falló");
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "en", "%1 operation denied, %2 isn't stoppable");
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "de", "%1-Operation verweigert, %2 ist nicht stopbar");
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "sv", "Operationen %1 nekades för att %2 inte kan stoppas");
Add(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, "es", "%1 operación denegada, %2 no se puede parar");
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "en", "%1 operation denied, %2 isn't removable");
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "de", "%1-Operation verweigert, %2 ist nicht wechselbar");
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "sv", "Operationen %1 nekades för att %2 inte är uttagbar(t)");
Add(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, "es", "%1 operación denegada, %2 no es removible");
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "en", "%1 operation denied, %2 isn't protectable");
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "de", "%1-Operation verweigert, %2 ist nicht schützbar");
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "sv", "Operationen %1 nekades för att %2 inte är skyddbar(t)");
Add(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, "es", "%1 operación denegada, %2 no es protegible");
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "en", "%1 operation denied, %2 isn't ready");
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit");
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "sv", "Operationen %1 nekades för att %2 inte är redo");
Add(LocalizationKey::ERROR_OPERATION_DENIED_READY, "es", "%1 operación denegada, %2 no está listo");
}
void Localizer::Add(LocalizationKey key, const string& locale, string_view value)
@ -200,7 +199,7 @@ string Localizer::Localize(LocalizationKey key, const string& locale, const stri
auto messages = it->second;
if (messages.empty()) {
return "Missing localization for enum value " + to_string(key);
return "Missing localization for enum value " + to_string((int)key);
}
string message = messages[key];

View File

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

View File

@ -71,7 +71,7 @@ DeviceFactory device_factory;
ControllerManager controller_manager;
RascsiImage rascsi_image;
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
SocketConnector socket_connector;
const SocketConnector socket_connector;
void DetachAll();
static void *MonThread(void *);
@ -139,9 +139,8 @@ bool InitService(int port)
}
// Create socket for monitor
sockaddr_in server;
sockaddr_in server = {};
monsocket = socket(PF_INET, SOCK_STREAM, 0);
memset(&server, 0, sizeof(server));
server.sin_family = PF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
@ -388,11 +387,11 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
const PbDeviceType type = pb_device.type();
if (controller_manager.GetDeviceByIdAndLun(id, unit) != nullptr) {
return ReturnLocalizedError(context, ERROR_DUPLICATE_ID, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_DUPLICATE_ID, to_string(id), to_string(unit));
}
if (unit >= AbstractController::LUN_MAX) {
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX));
if (unit >= ScsiController::LUN_MAX) {
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX));
}
string filename = GetParam(pb_device, "file");
@ -400,10 +399,10 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
PrimaryDevice *device = device_factory.CreateDevice(type, filename, id);
if (device == nullptr) {
if (type == UNDEFINED) {
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_TYPE, filename);
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
}
else {
return ReturnLocalizedError(context, ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
return ReturnLocalizedError(context, LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
}
}
@ -434,13 +433,13 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
}
}
else {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, PbDeviceType_Name(type));
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, PbDeviceType_Name(type));
}
}
@ -448,7 +447,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (file_support != nullptr && !device->IsRemovable() && filename.empty()) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
}
Filepath filepath;
@ -461,7 +460,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
try {
@ -475,7 +474,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
file_support->Open(filepath);
@ -484,7 +483,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
catch(const io_exception& e) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.get_msg());
return ReturnLocalizedError(context, LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
}
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
@ -510,7 +509,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!device->Init(params)) {
device_factory.DeleteDevice(*device);
return ReturnLocalizedError(context, ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
}
pthread_mutex_lock(&ctrl_mutex);
@ -518,7 +517,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!controller_manager.CreateScsiController(bus, device)) {
pthread_mutex_unlock(&ctrl_mutex);
return ReturnLocalizedError(context, ERROR_SCSI_CONTROLLER);
return ReturnLocalizedError(context, LocalizationKey::ERROR_SCSI_CONTROLLER);
}
pthread_mutex_unlock(&ctrl_mutex);
@ -541,7 +540,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
for (const Device *d : device_factory.GetAllDevices()) {
// LUN 0 can only be detached if there is no other LUN anymore
if (d->GetId() == device->GetId() && d->GetLun()) {
return ReturnLocalizedError(context, ERROR_LUN0);
return ReturnLocalizedError(context, LocalizationKey::ERROR_LUN0);
}
}
}
@ -561,7 +560,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
if (!controller_manager.FindController(id)->DeleteDevice(device)) {
pthread_mutex_unlock(&ctrl_mutex);
return ReturnLocalizedError(context, ERROR_DETACH);
return ReturnLocalizedError(context, LocalizationKey::ERROR_DETACH);
}
device_factory.DeleteDevice(*device);
pthread_mutex_unlock(&ctrl_mutex);
@ -575,16 +574,16 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device, Device *device, bool dryRun)
{
if (!device->IsRemoved()) {
return ReturnLocalizedError(context, ERROR_EJECT_REQUIRED);
return ReturnLocalizedError(context, LocalizationKey::ERROR_EJECT_REQUIRED);
}
if (!pb_device.vendor().empty() || !pb_device.product().empty() || !pb_device.revision().empty()) {
return ReturnLocalizedError(context, ERROR_DEVICE_NAME_UPDATE);
return ReturnLocalizedError(context, LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
}
string filename = GetParam(pb_device, "file");
if (filename.empty()) {
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
}
if (dryRun) {
@ -599,11 +598,11 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (pb_device.block_size()) {
if (disk != nullptr&& disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(device_factory, pb_device.block_size())) {
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
}
}
else {
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, device->GetType());
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, device->GetType());
}
}
@ -614,7 +613,7 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
string initial_filename = filepath.GetPath();
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
auto file_support = dynamic_cast<FileSupport *>(device);
@ -627,14 +626,14 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
filepath.SetPath((rascsi_image.GetDefaultImageFolder() + "/" + filename).c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
file_support->Open(filepath);
}
}
catch(const io_exception& e) { //NOSONAR This exception is handled properly
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.get_msg());
return ReturnLocalizedError(context, LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
}
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
@ -711,19 +710,19 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
// Check the Controller Number
if (id < 0) {
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID);
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_ID);
}
if (id >= ControllerManager::DEVICE_MAX) {
return ReturnLocalizedError(context, ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
}
if (operation == ATTACH && reserved_ids.find(id) != reserved_ids.end()) {
return ReturnLocalizedError(context, ERROR_RESERVED_ID, to_string(id));
return ReturnLocalizedError(context, LocalizationKey::ERROR_RESERVED_ID, to_string(id));
}
// Check the Unit Number
if (unit < 0 || unit >= AbstractController::LUN_MAX) {
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX - 1));
if (unit < 0 || unit >= ScsiController::LUN_MAX) {
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(unit), to_string(ScsiController::LUN_MAX - 1));
}
if (operation == ATTACH) {
@ -732,13 +731,13 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
// Does the controller exist?
if (!dryRun && controller_manager.FindController(id) == nullptr) {
return ReturnLocalizedError(context, ERROR_NON_EXISTING_DEVICE, to_string(id));
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_DEVICE, to_string(id));
}
// Does the unit exist?
PrimaryDevice *device = controller_manager.GetDeviceByIdAndLun(id, unit);
if (device == nullptr) {
return ReturnLocalizedError(context, ERROR_NON_EXISTING_UNIT, to_string(id), to_string(unit));
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_UNIT, to_string(id), to_string(unit));
}
if (operation == DETACH) {
@ -746,18 +745,18 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
}
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
}
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_READY, device->GetType());
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_READY, device->GetType());
}
switch (operation) {
@ -824,7 +823,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
break;
default:
return ReturnLocalizedError(context, ERROR_OPERATION);
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION);
}
return true;
@ -915,8 +914,8 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
unit = 0;
}
else if (!GetAsInt(id_spec.substr(0, separator_pos), id) || id < 0 || id > 7 ||
!GetAsInt(id_spec.substr(separator_pos + 1), unit) || unit < 0 || unit >= AbstractController::LUN_MAX) {
cerr << optarg << ": Invalid unit (0-" << (AbstractController::LUN_MAX - 1) << ")" << endl;
!GetAsInt(id_spec.substr(separator_pos + 1), unit) || unit < 0 || unit >= ScsiController::LUN_MAX) {
cerr << optarg << ": Invalid unit (0-" << (ScsiController::LUN_MAX - 1) << ")" << endl;
return false;
}
@ -925,7 +924,7 @@ bool ProcessId(const string& id_spec, int& id, int& unit)
void ShutDown(const CommandContext& context, const string& mode) {
if (mode.empty()) {
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_MISSING);
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
return;
}
@ -942,7 +941,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
// The root user has UID 0
if (getuid()) {
ReturnLocalizedError(context, ERROR_SHUTDOWN_PERMISSION);
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
return;
}
@ -969,7 +968,7 @@ void ShutDown(const CommandContext& context, const string& mode) {
}
}
else {
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_INVALID);
ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID);
}
}
@ -1132,7 +1131,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
command.set_operation(ATTACH);
Localizer localizer;
CommandContext context(&socket_connector, &localizer, -1, locale);
CommandContext context(socket_connector, localizer, -1, locale);
if (!ProcessCmd(context, command)) {
return false;
}
@ -1179,13 +1178,13 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
}
if (!access_token.empty() && access_token != GetParam(command, "token")) {
return ReturnLocalizedError(context, ERROR_AUTHENTICATION, UNAUTHORIZED);
return ReturnLocalizedError(context, LocalizationKey::ERROR_AUTHENTICATION, UNAUTHORIZED);
}
if (!PbOperation_IsValid(command.operation())) {
LOGERROR("Received unknown command with operation opcode %d", command.operation())
return ReturnLocalizedError(context, ERROR_OPERATION, UNKNOWN_OPERATION);
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION, UNKNOWN_OPERATION);
}
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str())
@ -1196,7 +1195,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
case LOG_LEVEL: {
string log_level = GetParam(command, "level");
if (bool status = SetLogLevel(log_level); !status) {
ReturnLocalizedError(context, ERROR_LOG_LEVEL, log_level);
ReturnLocalizedError(context, LocalizationKey::ERROR_LOG_LEVEL, log_level);
}
else {
ReturnStatus(context);
@ -1256,7 +1255,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
case IMAGE_FILE_INFO: {
if (string filename = GetParam(command, "file"); filename.empty()) {
ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
}
else {
auto image_file = make_unique<PbImageFile>();
@ -1267,7 +1266,7 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
socket_connector.SerializeMessage(context.fd, result);
}
else {
ReturnLocalizedError(context, ERROR_IMAGE_FILE_INFO);
ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_FILE_INFO);
}
}
break;
@ -1340,9 +1339,10 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
// Set up the monitor socket to receive commands
listen(monsocket, 1);
Localizer localizer;
while (true) {
Localizer localizer;
CommandContext context(&socket_connector, &localizer, -1, "");
CommandContext context(socket_connector, localizer, -1, "");
try {
PbCommand command;

View File

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

View File

@ -24,7 +24,7 @@ PbDeviceProperties *RascsiResponse::GetDeviceProperties(const Device *device)
{
auto properties = make_unique<PbDeviceProperties>().release();
properties->set_luns(AbstractController::LUN_MAX);
properties->set_luns(ScsiController::LUN_MAX);
properties->set_read_only(device->IsReadOnly());
properties->set_protectable(device->IsProtectable());
properties->set_stoppable(device->IsStoppable());
@ -56,7 +56,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
type_properties->set_type(type);
const PrimaryDevice *device = device_factory->CreateDevice(type, "", -1);
type_properties->set_allocated_properties(GetDeviceProperties(device));
device_factory->DeleteDevice(*device); //NOSONAR The alloced memory is managed by protobuf
device_factory->DeleteDevice(*device); //NOSONAR The allocated memory is managed by protobuf
}
void RascsiResponse::GetAllDeviceTypeProperties(PbDeviceTypesInfo& device_types_info)
@ -92,7 +92,7 @@ void RascsiResponse::GetDevice(const Device *device, PbDevice *pb_device)
status->set_removed(device->IsRemoved());
status->set_locked(device->IsLocked());
if (device->SupportsParams()) { //NOSONAR The alloced memory is managed by protobuf
if (device->SupportsParams()) { //NOSONAR The allocated memory is managed by protobuf
for (const auto& [key, value] : device->GetParams()) {
AddParam(*pb_device, key, value);
}
@ -111,7 +111,7 @@ void RascsiResponse::GetDevice(const Device *device, PbDevice *pb_device)
GetImageFile(image_file, device->IsRemovable() && !device->IsReady() ? "" : filepath.GetPath());
pb_device->set_allocated_file(image_file);
}
} //NOSONAR The alloced memory is managed by protobuf
} //NOSONAR The allocated memory is managed by protobuf
bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filename) const
{
@ -123,8 +123,7 @@ bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filenam
image_file->set_read_only(access(f.c_str(), W_OK));
struct stat st; //NOSONAR Cannot be declared in a separate statement because struct keyword is required
if (!stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
if (struct stat st; !stat(f.c_str(), &st) && !S_ISDIR(st.st_mode)) {
image_file->set_size(st.st_size);
return true;
}
@ -135,52 +134,57 @@ bool RascsiResponse::GetImageFile(PbImageFile *image_file, const string& filenam
void RascsiResponse::GetAvailableImages(PbImageFilesInfo& image_files_info, string_view default_image_folder,
const string& folder, const string& folder_pattern, const string& file_pattern, int scan_depth) {
if (scan_depth-- < 0) {
return;
}
string folder_pattern_lower = folder_pattern;
transform(folder_pattern_lower.begin(), folder_pattern_lower.end(), folder_pattern_lower.begin(), ::tolower);
string file_pattern_lower = file_pattern;
transform(file_pattern_lower.begin(), file_pattern_lower.end(), file_pattern_lower.begin(), ::tolower);
if (scan_depth-- >= 0) {
if (DIR *d = opendir(folder.c_str()); d) {
const dirent *dir;
while ((dir = readdir(d))) {
bool is_supported_type = dir->d_type == DT_REG || dir->d_type == DT_DIR || dir->d_type == DT_LNK || dir->d_type == DT_BLK;
if (is_supported_type && dir->d_name[0] != '.') {
string name_lower = dir->d_name;
if (!file_pattern.empty()) {
transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
}
DIR *d = opendir(folder.c_str());
if (d == nullptr) {
return;
}
string filename = folder + "/" + dir->d_name;
if (struct stat st; dir->d_type == DT_REG && !stat(filename.c_str(), &st)) {
if (!st.st_size) {
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
continue;
}
} else if (dir->d_type == DT_LNK && stat(filename.c_str(), &st)) {
LOGWARN("Symlink '%s' in image folder '%s' is broken", dir->d_name, folder.c_str())
continue;
} else if (dir->d_type == DT_DIR) {
if (folder_pattern_lower.empty() || name_lower.find(folder_pattern_lower) != string::npos) {
GetAvailableImages(image_files_info, default_image_folder, filename, folder_pattern,
file_pattern, scan_depth);
}
continue;
}
if (file_pattern_lower.empty() || name_lower.find(file_pattern_lower) != string::npos) {
if (auto image_file = make_unique<PbImageFile>(); GetImageFile(image_file.get(), filename)) {
GetImageFile(image_files_info.add_image_files(), filename.substr(default_image_folder.length() + 1));
}
}
}
const dirent *dir;
while ((dir = readdir(d))) {
bool is_supported_type = dir->d_type == DT_REG || dir->d_type == DT_DIR || dir->d_type == DT_LNK || dir->d_type == DT_BLK;
if (is_supported_type && dir->d_name[0] != '.') {
string name_lower = dir->d_name;
if (!file_pattern.empty()) {
transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);
}
closedir(d);
string filename = folder + "/" + dir->d_name;
if (struct stat st; dir->d_type == DT_REG && !stat(filename.c_str(), &st)) {
if (!st.st_size) {
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
continue;
}
} else if (dir->d_type == DT_LNK && stat(filename.c_str(), &st)) {
LOGWARN("Symlink '%s' in image folder '%s' is broken", dir->d_name, folder.c_str())
continue;
} else if (dir->d_type == DT_DIR) {
if (folder_pattern_lower.empty() || name_lower.find(folder_pattern_lower) != string::npos) {
GetAvailableImages(image_files_info, default_image_folder, filename, folder_pattern,
file_pattern, scan_depth);
}
continue;
}
if (file_pattern_lower.empty() || name_lower.find(file_pattern_lower) != string::npos) {
if (auto image_file = make_unique<PbImageFile>(); GetImageFile(image_file.get(), filename)) {
GetImageFile(image_files_info.add_image_files(), filename.substr(default_image_folder.length() + 1));
}
}
}
}
closedir(d);
}
PbImageFilesInfo *RascsiResponse::GetAvailableImages(PbResult& result, const string& folder_pattern,
@ -207,7 +211,7 @@ void RascsiResponse::GetAvailableImages(PbResult& result, PbServerInfo& server_i
image_files_info->set_default_image_folder(rascsi_image->GetDefaultImageFolder());
server_info.set_allocated_image_files_info(image_files_info);
result.set_status(true); //NOSONAR The alloced memory is managed by protobuf
result.set_status(true); //NOSONAR The allocated memory is managed by protobuf
}
PbReservedIdsInfo *RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids)
@ -278,14 +282,14 @@ PbServerInfo *RascsiResponse::GetServerInfo(PbResult& result, const unordered_se
auto server_info = make_unique<PbServerInfo>().release();
server_info->set_allocated_version_info(GetVersionInfo(result));
server_info->set_allocated_log_level_info(GetLogLevelInfo(result, current_log_level)); //NOSONAR The alloced memory is managed by protobuf
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info()); //NOSONAR The alloced memory is managed by protobuf
server_info->set_allocated_log_level_info(GetLogLevelInfo(result, current_log_level)); //NOSONAR The allocated memory is managed by protobuf
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info()); //NOSONAR The allocated memory is managed by protobuf
GetAvailableImages(result, *server_info, folder_pattern, file_pattern, scan_depth);
server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result));
server_info->set_allocated_mapping_info(GetMappingInfo(result)); //NOSONAR The alloced memory is managed by protobuf
GetDevices(*server_info); //NOSONAR The alloced memory is managed by protobuf
server_info->set_allocated_mapping_info(GetMappingInfo(result)); //NOSONAR The allocated memory is managed by protobuf
GetDevices(*server_info); //NOSONAR The allocated memory is managed by protobuf
server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids));
server_info->set_allocated_operation_info(GetOperationInfo(result, scan_depth)); //NOSONAR The alloced memory is managed by protobuf
server_info->set_allocated_operation_info(GetOperationInfo(result, scan_depth)); //NOSONAR The allocated memory is managed by protobuf
result.set_status(true);
@ -461,11 +465,11 @@ PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth)
PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation,
const string& description) const
{
auto meta_data = make_unique<PbOperationMetaData>();
auto meta_data = make_shared<PbOperationMetaData>();
meta_data->set_server_side_name(PbOperation_Name(operation));
meta_data->set_description(description);
int ordinal = PbOperation_descriptor()->FindValueByName(PbOperation_Name(operation))->index();
(*operation_info.mutable_operations())[ordinal] = *meta_data.release();
(*operation_info.mutable_operations())[ordinal] = *meta_data.get();
return &(*operation_info.mutable_operations())[ordinal];
}

View File

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

View File

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

View File

@ -10,23 +10,114 @@
#include "testing.h"
#include "controllers/abstract_controller.h"
TEST(AbstractControllerTest, Reset)
{
MockAbstractController controller(0);
controller.SetPhase(BUS::phase_t::status);
EXPECT_EQ(BUS::phase_t::status, controller.GetPhase());
controller.Reset();
EXPECT_TRUE(controller.IsBusFree());
}
TEST(AbstractControllerTest, SetGetStatus)
{
MockAbstractController controller(0);
controller.SetStatus(0x1234);
EXPECT_EQ(0x1234, controller.GetStatus());
}
TEST(AbstractControllerTest, SetPhase)
{
MockAbstractController controller(0);
controller.SetPhase(BUS::phase_t::selection);
EXPECT_TRUE(controller.IsSelection());
controller.SetPhase(BUS::phase_t::busfree);
EXPECT_TRUE(controller.IsBusFree());
controller.SetPhase(BUS::phase_t::command);
EXPECT_TRUE(controller.IsCommand());
controller.SetPhase(BUS::phase_t::status);
EXPECT_TRUE(controller.IsStatus());
controller.SetPhase(BUS::phase_t::datain);
EXPECT_TRUE(controller.IsDataIn());
controller.SetPhase(BUS::phase_t::dataout);
EXPECT_TRUE(controller.IsDataOut());
controller.SetPhase(BUS::phase_t::msgin);
EXPECT_TRUE(controller.IsMsgIn());
controller.SetPhase(BUS::phase_t::msgout);
EXPECT_TRUE(controller.IsMsgOut());
}
TEST(AbstractControllerTest, ProcessPhase)
{
MockAbstractController controller(0);
controller.SetPhase(BUS::phase_t::selection);
EXPECT_CALL(controller, Selection()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::busfree);
EXPECT_CALL(controller, BusFree()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::datain);
EXPECT_CALL(controller, DataIn()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::dataout);
EXPECT_CALL(controller, DataOut()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::command);
EXPECT_CALL(controller, Command()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::status);
EXPECT_CALL(controller, Status()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::msgin);
EXPECT_CALL(controller, MsgIn()).Times(1);
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::msgout);
EXPECT_CALL(controller, MsgOut()).Times(1);
controller.ProcessPhase();
}
TEST(AbstractControllerTest, DeviceLunLifeCycle)
{
const int ID = 1;
const int LUN = 4;
MockAbstractController controller(ID);
MockPrimaryDevice device;
MockPrimaryDevice device1;
MockPrimaryDevice device2;
device.SetLun(LUN);
EXPECT_FALSE(controller.HasLuns());
device1.SetLun(LUN);
device2.SetLun(32);
EXPECT_EQ(ID, controller.GetTargetId());
EXPECT_TRUE(controller.AddDevice(&device));
EXPECT_TRUE(controller.AddDevice(&device1));
EXPECT_FALSE(controller.AddDevice(&device2));
EXPECT_TRUE(controller.HasLuns());
EXPECT_TRUE(controller.HasDeviceForLun(LUN));
EXPECT_FALSE(controller.HasDeviceForLun(0));
EXPECT_EQ(&device, controller.GetDeviceForLun(LUN));
EXPECT_EQ(&device1, controller.GetDeviceForLun(LUN));
EXPECT_EQ(nullptr, controller.GetDeviceForLun(0));
EXPECT_TRUE(controller.DeleteDevice(&device));
EXPECT_TRUE(controller.DeleteDevice(&device1));
EXPECT_FALSE(controller.HasLuns());
}
TEST(AbstractControllerTest, ExtractInitiatorId)
@ -45,9 +136,9 @@ TEST(AbstractControllerTest, GetOpcode)
{
MockAbstractController controller(0);
controller.ctrl.cmd.resize(1);
vector<int>& cmd = controller.InitCmd(2);
controller.ctrl.cmd[0] = 0x12;
cmd[0] = 0x12;
EXPECT_EQ(0x12, (int)controller.GetOpcode());
}
@ -57,8 +148,16 @@ TEST(AbstractControllerTest, GetLun)
MockAbstractController controller(0);
controller.ctrl.cmd.resize(2);
vector<int>& cmd = controller.InitCmd(2);
controller.ctrl.cmd[1] = LUN << 5;
cmd[1] = LUN << 5;
EXPECT_EQ(LUN, controller.GetLun());
}
TEST(AbstractControllerTest, Ctrl)
{
MockAbstractController controller(0);
EXPECT_FALSE(controller.HasValidLength());
}

View File

@ -12,6 +12,7 @@
#include "rascsi_version.h"
#include "devices/device.h"
#include "devices/device_factory.h"
#include <unordered_map>
TEST(DeviceFactoryTest, GetTypeForFile)
{
@ -101,12 +102,64 @@ TEST(DeviceFactoryTest, GetSectorSizes)
EXPECT_TRUE(sector_sizes.find(2048) != sector_sizes.end());
}
TEST(DeviceFactoryTest, GetExtensionMapping)
{
DeviceFactory device_factory;
unordered_map<string, PbDeviceType> mapping = device_factory.GetExtensionMapping();
EXPECT_EQ(9, mapping.size());
EXPECT_EQ(SCHD, mapping["hd1"]);
EXPECT_EQ(SCHD, mapping["hds"]);
EXPECT_EQ(SCHD, mapping["hda"]);
EXPECT_EQ(SCHD, mapping["hdn"]);
EXPECT_EQ(SCHD, mapping["hdi"]);
EXPECT_EQ(SCHD, mapping["nhd"]);
EXPECT_EQ(SCRM, mapping["hdr"]);
EXPECT_EQ(SCMO, mapping["mos"]);
EXPECT_EQ(SCCD, mapping["iso"]);
}
TEST(DeviceFactoryTest, GetDefaultParams)
{
DeviceFactory device_factory;
unordered_map<string, string> params = device_factory.GetDefaultParams(SCHD);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCRM);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCMO);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCCD);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCHS);
EXPECT_TRUE(params.empty());
params = device_factory.GetDefaultParams(SCBR);
EXPECT_EQ(2, params.size());
params = device_factory.GetDefaultParams(SCDP);
EXPECT_EQ(2, params.size());
params = device_factory.GetDefaultParams(SCLP);
EXPECT_EQ(2, params.size());
}
TEST(DeviceFactoryTest, UnknownDeviceType)
{
DeviceFactory device_factory;
PrimaryDevice *device = device_factory.CreateDevice(UNDEFINED, "test", -1);
EXPECT_EQ(nullptr, device);
PrimaryDevice *device1 = device_factory.CreateDevice(UNDEFINED, "test", -1);
EXPECT_EQ(nullptr, device1);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
PrimaryDevice *device2 = device_factory.CreateDevice(SAHD, "test", -1);
#pragma GCC diagnostic pop
EXPECT_EQ(nullptr, device2);
}
TEST(DeviceFactoryTest, SCHD_Device_Defaults)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,14 +10,6 @@
#include "testing.h"
#include "controllers/scsi_controller.h"
TEST(ScsiControllerTest, Reset)
{
MockScsiController controller(nullptr, 0);
EXPECT_CALL(controller, SetPhase(BUS::phase_t::busfree)).Times(1);
controller.Reset();
}
TEST(ScsiControllerTest, GetMaxLuns)
{
MockScsiController controller(nullptr, 0);

View File

@ -20,16 +20,23 @@
#include "devices/scsimo.h"
#include "devices/host_services.h"
class MockAbstractController final : public AbstractController
class MockAbstractController final : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
{
FRIEND_TEST(AbstractControllerTest, Reset);
FRIEND_TEST(AbstractControllerTest, SetPhase);
FRIEND_TEST(AbstractControllerTest, ProcessPhase);
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
FRIEND_TEST(AbstractControllerTest, GetOpcode);
FRIEND_TEST(AbstractControllerTest, GetLun);
FRIEND_TEST(AbstractControllerTest, Ctrl);
public:
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
MOCK_METHOD(int, GetEffectiveLun, (), (const override));
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
MOCK_METHOD(int, GetInitiatorId, (), (const override));
MOCK_METHOD(void, SetUnit, (int), ());
MOCK_METHOD(void, Connect, (int, BUS *), ());
MOCK_METHOD(void, Status, (), ());
MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ());
@ -38,60 +45,15 @@ public:
MOCK_METHOD(void, Command, (), ());
MOCK_METHOD(void, MsgIn, (), ());
MOCK_METHOD(void, MsgOut, (), ());
MOCK_METHOD(void, Send, (), ());
MOCK_METHOD(bool, XferMsg, (int), ());
MOCK_METHOD(bool, XferIn, (BYTE *), ());
MOCK_METHOD(bool, XferOut, (bool), ());
MOCK_METHOD(void, ReceiveBytes, (), ());
MOCK_METHOD(void, Execute, (), ());
MOCK_METHOD(void, FlushUnit, (), ());
MOCK_METHOD(void, Receive, (), ());
MOCK_METHOD(bool, HasUnit, (), (const override));
MOCK_METHOD(void, SetByteTransfer, (bool), (override));
MOCK_METHOD(void, ScheduleShutdown, (rascsi_shutdown_mode), (override));
MOCK_METHOD(void, SetPhase, (BUS::phase_t), (override));
MOCK_METHOD(void, Reset, (), (override));
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
FRIEND_TEST(AbstractControllerTest, ExtractInitiatorId);
FRIEND_TEST(AbstractControllerTest, GetOpcode);
FRIEND_TEST(AbstractControllerTest, GetLun);
explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id) {}
explicit MockAbstractController(int target_id) : AbstractController(nullptr, target_id, 32) {}
~MockAbstractController() override = default;
int GetMaxLuns() const override { return 32; }
};
class MockScsiController final : public ScsiController
{
public:
MOCK_METHOD(BUS::phase_t, Process, (int), (override));
MOCK_METHOD(void, Error, (scsi_defs::sense_key, scsi_defs::asc, scsi_defs::status), (override));
MOCK_METHOD(int, GetInitiatorId, (), (const override));
MOCK_METHOD(void, SetUnit, (int), ());
MOCK_METHOD(void, Connect, (int, BUS *), ());
MOCK_METHOD(void, Status, (), ());
MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ());
MOCK_METHOD(void, BusFree, (), ());
MOCK_METHOD(void, Selection, (), ());
MOCK_METHOD(void, Command, (), ());
MOCK_METHOD(void, MsgIn, (), ());
MOCK_METHOD(void, MsgOut, (), ());
MOCK_METHOD(void, Send, (), ());
MOCK_METHOD(bool, XferMsg, (int), ());
MOCK_METHOD(bool, XferIn, (BYTE *), ());
MOCK_METHOD(bool, XferOut, (bool), ());
MOCK_METHOD(void, ReceiveBytes, (), ());
MOCK_METHOD(void, Execute, (), ());
MOCK_METHOD(void, FlushUnit, (), ());
MOCK_METHOD(void, Receive, (), ());
MOCK_METHOD(bool, HasUnit, (), (const override));
MOCK_METHOD(void, SetPhase, (BUS::phase_t), (override));
MOCK_METHOD(void, Sleep, (), ());
FRIEND_TEST(PrimaryDeviceTest, TestUnitReady);
FRIEND_TEST(PrimaryDeviceTest, Inquiry);
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
@ -109,6 +71,12 @@ public:
FRIEND_TEST(DiskTest, SynchronizeCache);
FRIEND_TEST(DiskTest, ReadDefectData);
public:
MOCK_METHOD(void, Status, (), ());
MOCK_METHOD(void, DataIn, (), ());
MOCK_METHOD(void, DataOut, (), ());
using ScsiController::ScsiController;
};
@ -131,14 +99,12 @@ class MockModePageDevice final : public ModePageDevice
{
FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages);
public:
MockModePageDevice() : ModePageDevice("test") {}
~MockModePageDevice() override = default;
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, BYTE *, int), (const override));
MOCK_METHOD(int, ModeSense10, (const vector<int>&, BYTE *, int), (const override));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&, int), (const override));
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<BYTE>&, int), (const override));
void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
// Return dummy data for other pages than page 0
@ -177,25 +143,21 @@ class MockSCSIHD_NEC final : public SCSIHD_NEC //NOSONAR Ignore inheritance hier
MOCK_METHOD(void, FlushCache, (), (override));
MockSCSIHD_NEC() = default;
~MockSCSIHD_NEC() override = default;
using SCSIHD_NEC::SCSIHD_NEC;
};
class MockSCSICD final : public SCSICD
{
FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages);
explicit MockSCSICD(const unordered_set<uint32_t>& sector_sizes) : SCSICD(sector_sizes) {}
~MockSCSICD() override = default;
using SCSICD::SCSICD;
};
class MockSCSIMO final : public SCSIMO
{
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages);
MockSCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries)
: SCSIMO(sector_sizes, geometries) {}
~MockSCSIMO() override = default;
using SCSIMO::SCSIMO;
};
class MockHostServices final : public HostServices