Cleanup (memory management, STL containers, type safety) based on SonarCloud report (#845)

* Removed static/global variable

* No need for ControllerManager as a singleton

* Updated factory handling

* Replaced loops

* Added const

* Added translations, fixed TODO, simplified operation creation

* Fixed SonarCloud warnings

* Replaced void * by BYTE *

* Added explicit mode_page_datetime struct

* Unit test updates

* Use enum classes

* Upddated file size check

* Use C++ output formatting

* Removed unused code

* Use array for garbage buffer

* Fixed data returned by READ CAPACITY(10)

* For mode pages: Replaced BYTE by std::byte

* Use std::byte for INQUIRY

* Use std::byte for REQUEST SENSE

* Replaced C array by vector

* Replaced C style array

* Replaced BYTE by std::byte

* Replaced DWORD

* Use more byte arreys

* Updated CTapDriver initialization/deletion

* Made status uint32_t instead of DWORD

* Replaced command byte array by vector

* Updated error handling

* Removed obsolete casts

* Improved locality of code

* rw_command has become obsolete

* Dynamically allocate command byte buffer

* Simplified receiving commands

* Use references

* Type safety update, dispatcher update

* Removed macros, replaced BOOL/FALSE/TRUE
This commit is contained in:
Uwe Seimet 2022-09-21 08:27:51 +02:00 committed by GitHub
parent 241e739d3a
commit 119dd55ef0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 1401 additions and 1628 deletions

View File

@ -19,7 +19,7 @@
//---------------------------------------------------------------------------
#define USE_SEL_EVENT_ENABLE // Check SEL signal by event
// This avoids an indefinite loop with warnings if there is no RaSCSI hardware
// and thus helps with running rasctl and unit test on other hardware.
#if !defined(__arm__)
// and thus helps with running rasctl and unit test on x86 hardware.
#if defined(__x86_64__) || defined(__X86__)
#undef USE_SEL_EVENT_ENABLE
#endif

View File

@ -13,6 +13,7 @@
#include "phase_handler.h"
#include <unordered_map>
#include <vector>
#include <memory>
using namespace std;
@ -33,20 +34,16 @@ public:
RESTART_PI
};
// Internal data definition
// TODO Some of these data are probably device specific, and in this case they should be moved.
// These data are not internal, otherwise they could all be private
using ctrl_t = struct _ctrl_t {
// General
BUS::phase_t phase = BUS::busfree; // Transition phase
BUS::phase_t phase = BUS::phase_t::busfree; // Transition phase
// commands
DWORD cmd[16]; // Command data
DWORD status; // Status data
vector<int> cmd; // Command data, dynamically allocated per received command
uint32_t status; // Status data
int message; // Message data
// Transfer
// TODO Try to get rid of the static buffer
BYTE *buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size
uint32_t blocks; // Number of transfer blocks
@ -58,7 +55,7 @@ public:
unordered_map<int, PrimaryDevice *> luns;
};
AbstractController(shared_ptr<BUS> bus, int target_id) : bus(bus), target_id(target_id) {}
AbstractController(shared_ptr<BUS> bus, int target_id) : target_id(target_id), bus(bus) {}
~AbstractController() override = default;
AbstractController(AbstractController&) = delete;
AbstractController& operator=(const AbstractController&) = delete;
@ -89,14 +86,13 @@ public:
// TODO Do not expose internal data
ctrl_t* GetCtrl() { return &ctrl; }
int target_id;
protected:
scsi_defs::scsi_command GetOpcode() const { return (scsi_defs::scsi_command)ctrl.cmd[0]; }
shared_ptr<BUS> bus;
ctrl_t ctrl = {};
private:
int target_id;
};

View File

@ -15,13 +15,7 @@
using namespace std;
ControllerManager& ControllerManager::instance()
{
static ControllerManager instance;
return instance;
}
bool ControllerManager::CreateScsiController(shared_ptr<BUS> bus, PrimaryDevice *device) const
bool ControllerManager::CreateScsiController(shared_ptr<BUS> bus, PrimaryDevice *device)
{
shared_ptr<AbstractController> controller = FindController(device->GetId());
if (controller == nullptr) {
@ -49,7 +43,7 @@ shared_ptr<AbstractController> ControllerManager::FindController(int target_id)
return it == controllers.end() ? nullptr : it->second;
}
void ControllerManager::DeleteAllControllers() const
void ControllerManager::DeleteAllControllers()
{
controllers.clear();
}

View File

@ -22,23 +22,23 @@ class PrimaryDevice;
class ControllerManager
{
public:
ControllerManager() = default;
~ControllerManager() = default;
ControllerManager(ControllerManager&) = delete;
ControllerManager& operator=(const ControllerManager&) = delete;
public:
// Maximum number of controller devices
static const int DEVICE_MAX = 8;
static ControllerManager& instance();
bool CreateScsiController(shared_ptr<BUS>, PrimaryDevice *) const;
bool CreateScsiController(shared_ptr<BUS>, PrimaryDevice *);
shared_ptr<AbstractController> IdentifyController(int) const;
shared_ptr<AbstractController> FindController(int) const;
void DeleteAllControllers() const;
void DeleteAllControllers();
void ResetAllControllers() const;
PrimaryDevice *GetDeviceByIdAndLun(int, int) const;
inline static unordered_map<int, shared_ptr<AbstractController>> controllers;
unordered_map<int, shared_ptr<AbstractController>> controllers;
};

View File

@ -21,6 +21,8 @@
#include "devices/scsi_host_bridge.h"
#include "devices/scsi_daynaport.h"
#include "scsi_controller.h"
#include <sstream>
#include <iomanip>
using namespace scsi_defs;
@ -39,7 +41,7 @@ ScsiController::~ScsiController()
void ScsiController::Reset()
{
SetPhase(BUS::busfree);
SetPhase(BUS::phase_t::busfree);
ctrl.status = 0x00;
ctrl.message = 0x00;
execstart = 0;
@ -92,35 +94,35 @@ BUS::phase_t ScsiController::Process(int id)
try {
// Phase processing
switch (ctrl.phase) {
case BUS::busfree:
case BUS::phase_t::busfree:
BusFree();
break;
case BUS::selection:
case BUS::phase_t::selection:
Selection();
break;
case BUS::dataout:
case BUS::phase_t::dataout:
DataOut();
break;
case BUS::datain:
case BUS::phase_t::datain:
DataIn();
break;
case BUS::command:
case BUS::phase_t::command:
Command();
break;
case BUS::status:
case BUS::phase_t::status:
Status();
break;
case BUS::msgout:
case BUS::phase_t::msgout:
MsgOut();
break;
case BUS::msgin:
case BUS::phase_t::msgin:
MsgIn();
break;
@ -146,10 +148,10 @@ BUS::phase_t ScsiController::Process(int id)
void ScsiController::BusFree()
{
if (ctrl.phase != BUS::busfree) {
if (ctrl.phase != BUS::phase_t::busfree) {
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__)
SetPhase(BUS::busfree);
SetPhase(BUS::phase_t::busfree);
bus->SetREQ(false);
bus->SetMSG(false);
@ -206,7 +208,7 @@ void ScsiController::BusFree()
void ScsiController::Selection()
{
if (ctrl.phase != BUS::selection) {
if (ctrl.phase != BUS::phase_t::selection) {
// A different device controller was selected
if (int id = 1 << GetTargetId(); (bus->GetDAT() & id) == 0) {
return;
@ -219,7 +221,7 @@ void ScsiController::Selection()
LOGTRACE("%s Selection Phase Target ID=%d", __PRETTY_FUNCTION__, GetTargetId())
SetPhase(BUS::selection);
SetPhase(BUS::phase_t::selection);
// Raise BSY and respond
bus->SetBSY(true);
@ -239,45 +241,37 @@ void ScsiController::Selection()
void ScsiController::Command()
{
if (ctrl.phase != BUS::command) {
if (ctrl.phase != BUS::phase_t::command) {
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__)
SetPhase(BUS::command);
SetPhase(BUS::phase_t::command);
bus->SetMSG(false);
bus->SetCD(true);
bus->SetIO(false);
// Data transfer is 6 bytes x 1 block
ctrl.offset = 0;
ctrl.length = 6;
ctrl.blocks = 1;
// If no byte can be received move to the status phase
int command_byte_count = bus->CommandHandShake(ctrl.buffer);
if (!command_byte_count) {
LOGERROR("%s No command bytes received", __PRETTY_FUNCTION__)
Error(sense_key::ABORTED_COMMAND);
return;
}
ctrl.length = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
int actual_count = bus->CommandHandShake(ctrl.buffer);
int command_byte_count = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
// If not able to receive all, move to the status phase
if (command_byte_count != (int)ctrl.length) {
if (actual_count != command_byte_count) {
LOGERROR("%s Command byte count mismatch: expected %d bytes, received %d byte(s)", __PRETTY_FUNCTION__,
command_byte_count, actual_count)
Error(sense_key::ABORTED_COMMAND);
return;
}
// Command data transfer
for (int i = 0; i < (int)ctrl.length; i++) {
ctrl.cmd[i] = ctrl.buffer[i];
LOGTRACE("%s CDB[%d]=$%02X",__PRETTY_FUNCTION__, i, ctrl.cmd[i])
}
ctrl.cmd.resize(command_byte_count);
// Command data transfer
stringstream s;
for (int i = 0; i < command_byte_count; i++) {
ctrl.cmd[i] = ctrl.buffer[i];
s << setfill('0') << setw(2) << hex << ctrl.cmd[i];
}
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str())
// Clear length and block
ctrl.length = 0;
ctrl.blocks = 0;
Execute();
}
@ -285,9 +279,9 @@ void ScsiController::Command()
void ScsiController::Execute()
{
LOGTRACE("%s Execution phase command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
LOGDEBUG("++++ CMD ++++ %s Executing command $%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
SetPhase(BUS::execute);
SetPhase(BUS::phase_t::execute);
// Initialization for data transfer
ctrl.offset = 0;
@ -295,16 +289,13 @@ void ScsiController::Execute()
execstart = SysTimer::GetTimerLow();
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
if (GetOpcode() != scsi_command::eCmdRequestSense) {
ctrl.status = 0;
}
LOGDEBUG("++++ CMD ++++ %s Executing command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun)) {
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdInquiry &&
(scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
if (GetOpcode() != scsi_command::eCmdInquiry && GetOpcode() != scsi_command::eCmdRequestSense) {
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetTargetId())
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
@ -322,13 +313,13 @@ void ScsiController::Execute()
PrimaryDevice *device = GetDeviceForLun(lun);
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
if (GetOpcode() != scsi_command::eCmdRequestSense) {
device->SetStatusCode(0);
}
try {
if (!device->Dispatch()) {
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (BYTE)ctrl.cmd[0])
if (!device->Dispatch(GetOpcode())) {
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (int)GetOpcode())
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
}
@ -340,7 +331,7 @@ void ScsiController::Execute()
}
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if ((scsi_command)ctrl.cmd[0] == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) {
if (GetOpcode() == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) {
lun = GetEffectiveLun();
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, device->GetId())
@ -351,7 +342,7 @@ void ScsiController::Execute()
void ScsiController::Status()
{
if (ctrl.phase != BUS::status) {
if (ctrl.phase != BUS::phase_t::status) {
// Minimum execution time
if (execstart > 0) {
Sleep();
@ -359,9 +350,9 @@ void ScsiController::Status()
SysTimer::SleepUsec(5);
}
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status)
LOGTRACE("%s Status Phase $%02X",__PRETTY_FUNCTION__, ctrl.status)
SetPhase(BUS::status);
SetPhase(BUS::phase_t::status);
// Signal line operated by the target
bus->SetMSG(false);
@ -382,10 +373,10 @@ void ScsiController::Status()
void ScsiController::MsgIn()
{
if (ctrl.phase != BUS::msgin) {
if (ctrl.phase != BUS::phase_t::msgin) {
LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__)
SetPhase(BUS::msgin);
SetPhase(BUS::phase_t::msgin);
bus->SetMSG(true);
bus->SetCD(true);
@ -406,17 +397,17 @@ void ScsiController::MsgOut()
{
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId())
if (ctrl.phase != BUS::msgout) {
if (ctrl.phase != BUS::phase_t::msgout) {
LOGTRACE("Message Out Phase")
// process the IDENTIFY message
if (ctrl.phase == BUS::selection) {
if (ctrl.phase == BUS::phase_t::selection) {
scsi.atnmsg = true;
scsi.msc = 0;
memset(scsi.msb, 0x00, sizeof(scsi.msb));
}
SetPhase(BUS::msgout);
SetPhase(BUS::phase_t::msgout);
bus->SetMSG(true);
bus->SetCD(true);
@ -435,7 +426,7 @@ void ScsiController::MsgOut()
void ScsiController::DataIn()
{
if (ctrl.phase != BUS::datain) {
if (ctrl.phase != BUS::phase_t::datain) {
// Minimum execution time
if (execstart > 0) {
Sleep();
@ -449,7 +440,7 @@ void ScsiController::DataIn()
LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__)
SetPhase(BUS::datain);
SetPhase(BUS::phase_t::datain);
bus->SetMSG(false);
bus->SetCD(false);
@ -467,7 +458,7 @@ void ScsiController::DataIn()
void ScsiController::DataOut()
{
if (ctrl.phase != BUS::dataout) {
if (ctrl.phase != BUS::phase_t::dataout) {
// Minimum execution time
if (execstart > 0) {
Sleep();
@ -481,7 +472,7 @@ void ScsiController::DataOut()
LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__)
SetPhase(BUS::dataout);
SetPhase(BUS::phase_t::dataout);
// Signal line operated by the target
bus->SetMSG(false);
@ -509,24 +500,24 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
}
// Bus free for status phase and message in phase
if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) {
if (ctrl.phase == BUS::phase_t::status || ctrl.phase == BUS::phase_t::msgin) {
BusFree();
return;
}
int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun) || asc == INVALID_LUN) {
if (!HasDeviceForLun(lun) || asc == asc::INVALID_LUN) {
assert(HasDeviceForLun(0));
lun = 0;
}
if (sense_key || asc) {
if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
// Set Sense Key and ASC for a subsequent REQUEST SENSE
GetDeviceForLun(lun)->SetStatusCode((sense_key << 16) | (asc << 8));
GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
}
ctrl.status = status;
ctrl.status = (uint32_t)status;
ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__)
@ -564,7 +555,7 @@ void ScsiController::Send()
bool result = true;
// Processing after data collection (read/data-in only)
if (ctrl.phase == BUS::datain && ctrl.blocks != 0) {
if (ctrl.phase == BUS::phase_t::datain && ctrl.blocks != 0) {
// set next buffer (set offset, length)
result = XferIn(ctrl.buffer);
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Processing after data collection. Blocks: " + to_string(ctrl.blocks)).c_str())
@ -585,10 +576,10 @@ void ScsiController::Send()
}
// Move to next phase
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), ctrl.phase)
LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), (int)ctrl.phase)
switch (ctrl.phase) {
// Message in phase
case BUS::msgin:
case BUS::phase_t::msgin:
// Completed sending response to extended message of IDENTIFY message
if (scsi.atnmsg) {
// flag off
@ -603,13 +594,13 @@ void ScsiController::Send()
break;
// Data-in Phase
case BUS::datain:
case BUS::phase_t::datain:
// status phase
Status();
break;
// status phase
case BUS::status:
case BUS::phase_t::status:
// Message in phase
ctrl.length = 1;
ctrl.blocks = 1;
@ -641,13 +632,13 @@ void ScsiController::Receive()
// Length != 0 if received
if (ctrl.length != 0) {
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, (int)ctrl.length)
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length)
// Receive
len = bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
// If not able to receive all, move to status phase
if (len != (int)ctrl.length) {
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, (int)ctrl.length, len)
LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, ctrl.length, len)
Error(sense_key::ABORTED_COMMAND);
return;
}
@ -665,7 +656,7 @@ void ScsiController::Receive()
// Processing after receiving data (by phase)
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
switch (ctrl.phase) {
case BUS::dataout:
case BUS::phase_t::dataout:
if (ctrl.blocks == 0) {
// End with this buffer
result = XferOut(false);
@ -675,7 +666,7 @@ void ScsiController::Receive()
}
break;
case BUS::msgout:
case BUS::phase_t::msgout:
ctrl.message = ctrl.buffer[0];
if (!XferMsg(ctrl.message)) {
// Immediately free the bus if message output fails
@ -706,7 +697,7 @@ void ScsiController::Receive()
// Move to next phase
switch (ctrl.phase) {
case BUS::command:
case BUS::phase_t::command:
len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
for (int i = 0; i < len; i++) {
@ -717,7 +708,7 @@ void ScsiController::Receive()
Execute();
break;
case BUS::msgout:
case BUS::phase_t::msgout:
// Continue message out phase as long as ATN keeps asserting
if (bus->GetATN()) {
// Data transfer is 1 byte x 1 block
@ -801,7 +792,7 @@ void ScsiController::Receive()
Command();
break;
case BUS::dataout:
case BUS::phase_t::dataout:
FlushUnit();
Status();
@ -815,7 +806,7 @@ void ScsiController::Receive()
bool ScsiController::XferMsg(int msg)
{
assert(ctrl.phase == BUS::msgout);
assert(ctrl.phase == BUS::phase_t::msgout);
// Save message out data
if (scsi.atnmsg) {
@ -866,11 +857,11 @@ void ScsiController::ReceiveBytes()
LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase))
switch (ctrl.phase) {
case BUS::dataout:
case BUS::phase_t::dataout:
result = XferOut(false);
break;
case BUS::msgout:
case BUS::phase_t::msgout:
ctrl.message = ctrl.buffer[0];
if (!XferMsg(ctrl.message)) {
// Immediately free the bus if message output fails
@ -894,7 +885,7 @@ void ScsiController::ReceiveBytes()
// Move to next phase
switch (ctrl.phase) {
case BUS::command:
case BUS::phase_t::command:
len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
for (uint32_t i = 0; i < len; i++) {
@ -905,7 +896,7 @@ void ScsiController::ReceiveBytes()
Execute();
break;
case BUS::msgout:
case BUS::phase_t::msgout:
// Continue message out phase as long as ATN keeps asserting
if (bus->GetATN()) {
// Data transfer is 1 byte x 1 block
@ -989,7 +980,7 @@ void ScsiController::ReceiveBytes()
Command();
break;
case BUS::dataout:
case BUS::phase_t::dataout:
Status();
break;
@ -1001,7 +992,7 @@ void ScsiController::ReceiveBytes()
bool ScsiController::XferOut(bool cont)
{
assert(ctrl.phase == BUS::dataout);
assert(ctrl.phase == BUS::phase_t::dataout);
if (!is_byte_transfer) {
return XferOutBlockOriented(cont);
@ -1010,18 +1001,18 @@ bool ScsiController::XferOut(bool cont)
is_byte_transfer = false;
if (auto device = GetDeviceForLun(GetEffectiveLun());
device != nullptr && ctrl.cmd[0] == scsi_command::eCmdWrite6) {
device != nullptr && GetOpcode() == scsi_command::eCmdWrite6) {
return device->WriteByteSequence(ctrl.buffer, bytes_to_transfer);
}
LOGWARN("Received an unexpected command ($%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
LOGWARN("Received an unexpected command ($%02X) in %s", (int)GetOpcode(), __PRETTY_FUNCTION__)
return false;
}
void ScsiController::FlushUnit()
{
assert(ctrl.phase == BUS::dataout);
assert(ctrl.phase == BUS::phase_t::dataout);
auto disk = dynamic_cast<Disk *>(GetDeviceForLun(GetEffectiveLun()));
if (disk == nullptr) {
@ -1029,18 +1020,18 @@ void ScsiController::FlushUnit()
}
// WRITE system only
switch ((ScsiController::rw_command)ctrl.cmd[0]) {
case ScsiController::eRwCmdWrite6:
case ScsiController::eRwCmdWrite10:
case ScsiController::eRwCmdWrite16:
case ScsiController::eRwCmdWriteLong10:
case ScsiController::eRwCmdWriteLong16:
case ScsiController::eRwCmdVerify10:
case ScsiController::eRwCmdVerify16:
switch (GetOpcode()) {
case scsi_command::eCmdWrite6:
case scsi_command::eCmdWrite10:
case scsi_command::eCmdWrite16:
case scsi_command::eCmdWriteLong10:
case scsi_command::eCmdWriteLong16:
case scsi_command::eCmdVerify10:
case scsi_command::eCmdVerify16:
break;
case ScsiController::eRwCmdModeSelect6:
case ScsiController::eRwCmdModeSelect10:
case scsi_command::eCmdModeSelect6:
case scsi_command::eCmdModeSelect10:
// TODO What is this special handling of ModeSelect good for?
// 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?
@ -1048,18 +1039,18 @@ void ScsiController::FlushUnit()
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
}
catch(const scsi_error_exception& e) {
LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0])
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
Error(e.get_sense_key(), e.get_asc(), e.get_status());
return;
}
break;
case ScsiController::eRwCmdSetMcastAddr:
case scsi_command::eCmdSetMcastAddr:
// TODO: Eventually, we should store off the multicast address configuration data here...
break;
default:
LOGWARN("Received an unexpected flush command $%02X\n",(WORD)ctrl.cmd[0])
LOGWARN("Received an unexpected flush command $%02X\n", (int)GetOpcode())
break;
}
}
@ -1074,9 +1065,9 @@ void ScsiController::FlushUnit()
//---------------------------------------------------------------------------
bool ScsiController::XferIn(BYTE *buf)
{
assert(ctrl.phase == BUS::datain);
assert(ctrl.phase == BUS::phase_t::datain);
LOGTRACE("%s ctrl.cmd[0]=%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0])
LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, (int)GetOpcode())
int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun)) {
@ -1084,13 +1075,13 @@ bool ScsiController::XferIn(BYTE *buf)
}
// Limited to read commands
switch (ctrl.cmd[0]) {
case eRwCmdRead6:
case eRwCmdRead10:
case eRwCmdRead16:
switch (GetOpcode()) {
case scsi_command::eCmdRead6:
case scsi_command::eCmdRead10:
case scsi_command::eCmdRead16:
// Read from disk
try {
ctrl.length = ((Disk *)GetDeviceForLun(lun))->Read(ctrl.cmd, buf, ctrl.next);
ctrl.length = (static_cast<Disk *>(GetDeviceForLun(lun)))->Read(ctrl.cmd, buf, ctrl.next);
}
catch(const scsi_error_exception&) {
// If there is an error, go to the status phase
@ -1109,7 +1100,6 @@ bool ScsiController::XferIn(BYTE *buf)
return false;
}
// Succeeded in setting the buffer
return true;
}
@ -1129,9 +1119,9 @@ bool ScsiController::XferOutBlockOriented(bool cont)
}
// Limited to write commands
switch (ctrl.cmd[0]) {
case eRwCmdModeSelect6:
case eRwCmdModeSelect10:
switch (GetOpcode()) {
case scsi_command::eCmdModeSelect6:
case scsi_command::eCmdModeSelect10:
try {
disk->ModeSelect(ctrl.cmd, ctrl.buffer, ctrl.offset);
}
@ -1141,12 +1131,12 @@ bool ScsiController::XferOutBlockOriented(bool cont)
}
break;
case eRwCmdWrite6:
case eRwCmdWrite10:
case eRwCmdWrite16:
case scsi_command::eCmdWrite6:
case scsi_command::eCmdWrite10:
case scsi_command::eCmdWrite16:
// TODO Verify has to verify, not to write
case eRwCmdVerify10:
case eRwCmdVerify16:
case scsi_command::eCmdVerify10:
case scsi_command::eCmdVerify16:
{
// Special case Write function for brige
// TODO This class must not know about SCSIBR
@ -1199,12 +1189,12 @@ bool ScsiController::XferOutBlockOriented(bool cont)
break;
}
case eRwCmdSetMcastAddr:
case scsi_command::eCmdSetMcastAddr:
LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__)
break;
default:
LOGWARN("Received an unexpected command ($%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
LOGWARN("Received an unexpected command ($%02X) in %s", (int)GetOpcode(), __PRETTY_FUNCTION__)
break;
}

View File

@ -37,23 +37,6 @@ class ScsiController : public AbstractController
const int DEFAULT_BUFFER_SIZE = 0x1000;
enum rw_command : int {
eRwCmdRead6 = 0x08,
eRwCmdWrite6 = 0x0A,
eRwCmdSetMcastAddr = 0x0D, // DaynaPort specific command
eRwCmdModeSelect6 = 0x15,
eRwCmdRead10 = 0x28,
eRwCmdWrite10 = 0x2A,
eRwCmdVerify10 = 0x2E,
eRwCmdVerify = 0x2F,
eRwCmdModeSelect10 = 0x55,
eRwCmdRead16 = 0x88,
eRwCmdWrite16 = 0x8A,
eRwCmdVerify16 = 0x8F,
eRwCmdWriteLong10 = 0x3F,
eRwCmdWriteLong16 = 0x9F
};
using scsi_t = struct _scsi_t {
// Synchronous transfer
bool syncenable; // Synchronous transfer possible
@ -95,7 +78,7 @@ public:
private:
// Execution start time
DWORD execstart = 0;
uint32_t execstart = 0;
// The initiator ID may be unavailable, e.g. with Atari ACSI and old host adapters
int initiator_id = UNKNOWN_INITIATOR_ID;

View File

@ -108,8 +108,7 @@ void Human68k::namests_t::GetCopyPath(BYTE* szPath) const
ASSERT(szPath);
BYTE* p = szPath;
for (size_t i = 0; i < 65; i++) {
BYTE c = path[i];
for (BYTE c : path) {
if (c == '\0')
break;
if (c == 0x09) {
@ -226,10 +225,10 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
{
ASSERT(szBase);
ASSERT(strlen(szBase) < FILEPATH_MAX);
ASSERT(m_bWriteProtect == FALSE);
ASSERT(m_bEnable == FALSE);
ASSERT(!m_bWriteProtect);
ASSERT(!m_bEnable);
ASSERT(m_capCache.sectors == 0);
ASSERT(m_bVolumeCache == FALSE);
ASSERT(!m_bVolumeCache);
ASSERT(m_szVolumeCache[0] == _T('\0'));
// Confirm that the entity does not exist (just in case)
@ -241,7 +240,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
// Receive parameters
if (nFlag & FSFLAG_WRITE_PROTECT)
m_bWriteProtect = TRUE;
m_bWriteProtect = true;
strcpy(m_szBase, szBase);
// Remove the last path delimiter in the base path
@ -268,7 +267,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
*pClear = _T('\0');
// Status update
m_bEnable = TRUE;
m_bEnable = true;
}
//---------------------------------------------------------------------------
@ -276,10 +275,10 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
// Media check
//
//---------------------------------------------------------------------------
BOOL CHostDrv::isMediaOffline() const
bool CHostDrv::isMediaOffline() const
{
// Offline status check
return m_bEnable == FALSE;
return !m_bEnable;
}
//---------------------------------------------------------------------------
@ -307,14 +306,14 @@ DWORD CHostDrv::GetStatus() const
// Media status settings
//
//---------------------------------------------------------------------------
void CHostDrv::SetEnable(BOOL bEnable)
void CHostDrv::SetEnable(bool bEnable)
{
m_bEnable = bEnable;
if (bEnable == FALSE) {
if (!bEnable) {
// Clear cache
m_capCache.sectors = 0;
m_bVolumeCache = FALSE;
m_bVolumeCache = false;
m_szVolumeCache[0] = _T('\0');
}
}
@ -324,11 +323,11 @@ void CHostDrv::SetEnable(BOOL bEnable)
// Media change check
//
//---------------------------------------------------------------------------
BOOL CHostDrv::CheckMedia()
bool CHostDrv::CheckMedia()
{
// Status update
Update();
if (m_bEnable == FALSE)
if (!m_bEnable)
CleanCache();
return m_bEnable;
@ -342,10 +341,8 @@ BOOL CHostDrv::CheckMedia()
void CHostDrv::Update()
{
// Considered as media insertion
BOOL bEnable = TRUE;
// Media status reflected
SetEnable(bEnable);
SetEnable(true);
}
//---------------------------------------------------------------------------
@ -357,7 +354,7 @@ void CHostDrv::Eject()
{
// Media discharge
CleanCache();
SetEnable(FALSE);
SetEnable(false);
// Status update
Update();
@ -382,7 +379,7 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
}
// Cache update
m_bVolumeCache = TRUE;
m_bVolumeCache = true;
// Transfer content
strcpy(szLabel, m_szVolumeCache);
@ -393,10 +390,10 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
/// Get volume label from cache
///
/// Transfer the cached volume label information.
/// If the cache contents are valid return TRUE, if invalid return FALSE.
/// Return true if the cache contents are valid.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
bool CHostDrv::GetVolumeCache(TCHAR* szLabel) const
{
ASSERT(szLabel);
@ -406,11 +403,6 @@ BOOL CHostDrv::GetVolumeCache(TCHAR* szLabel) const
return m_bVolumeCache;
}
//---------------------------------------------------------------------------
//
/// Get Capacity
//
//---------------------------------------------------------------------------
DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
{
ASSERT(pCapacity);
@ -447,12 +439,12 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
/// Get capacity from the cache
///
/// Transfer the capacity data stored in cache.
/// If the contents of the cache is valid return TRUE, is invalid return FALSE.
/// Return true if the contents of the cache are valid.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
bool CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
{
ASSERT(pCapacity);
assert(pCapacity);
// Transfer contents
memcpy(pCapacity, &m_capCache, sizeof(m_capCache));
@ -480,7 +472,7 @@ void CHostDrv::CleanCache() const
//---------------------------------------------------------------------------
void CHostDrv::CleanCache(const BYTE* szHumanPath)
{
ASSERT(szHumanPath);
assert(szHumanPath);
CHostPath* p = FindCache(szHumanPath);
if (p) {
@ -513,8 +505,6 @@ void CHostDrv::CleanCacheChild(const BYTE* szHumanPath) const
//---------------------------------------------------------------------------
void CHostDrv::DeleteCache(const BYTE* szHumanPath)
{
ASSERT(szHumanPath);
auto p = FindCache(szHumanPath);
if (p) {
delete p;
@ -712,7 +702,7 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
/// Set all Human68k parameters once more.
//
//---------------------------------------------------------------------------
BOOL CHostDrv::Find(CHostFiles* pFiles)
bool CHostDrv::Find(CHostFiles* pFiles)
{
ASSERT(pFiles);
@ -722,7 +712,7 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
pPath = MakeCache(pFiles);
if (pPath == nullptr) {
CleanCache();
return FALSE; // Error: Failed to build cache
return false; // Error: Failed to build cache
}
}
@ -731,13 +721,13 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
// Exit if only path name
if (pFiles->isPathOnly()) {
return TRUE; // Normal exit: only path name
return true; // Normal exit: only path name
}
// Find file name
const CHostFilename* pFilename = pFiles->Find(pPath);
if (pFilename == nullptr) {
return FALSE; // Error: Could not get file name
return false; // Error: Could not get file name
}
// Store the Human68k side search results
@ -746,7 +736,7 @@ BOOL CHostDrv::Find(CHostFiles* pFiles)
// Store the host side full path name
pFiles->AddResult(pFilename->GetHost());
return TRUE;
return true;
}
//===========================================================================
@ -809,7 +799,7 @@ void CHostFilename::ConvertHuman(int nCount)
(m_szHost[1] == _T('\0') || (m_szHost[1] == _T('.') && m_szHost[2] == _T('\0')))) {
strcpy((char*)m_szHuman, m_szHost);
m_bCorrect = TRUE;
m_bCorrect = true;
m_pszHumanLast = m_szHuman + strlen((const char*)m_szHuman);
m_pszHumanExt = m_pszHumanLast;
return;
@ -1002,22 +992,22 @@ void CHostFilename::ConvertHuman(int nCount)
*pWrite = '\0';
// Confirm the conversion results
m_bCorrect = TRUE;
m_bCorrect = true;
// Fail if the base file name does not exist
if (m_pszHumanExt <= m_szHuman)
m_bCorrect = FALSE;
m_bCorrect = false;
// Fail if the base file name is more than 1 char and ends with a space
// While it is theoretically valid to have a base file name exceed 8 chars,
// Human68k is unable to handle it, so failing this case too.
else if (m_pszHumanExt[-1] == ' ')
m_bCorrect = FALSE;
m_bCorrect = false;
// Fail if the conversion result is the same as a special directory name
if (m_szHuman[0] == '.' &&
(m_szHuman[1] == '\0' || (m_szHuman[1] == '.' && m_szHuman[2] == '\0')))
m_bCorrect = FALSE;
m_bCorrect = false;
}
//---------------------------------------------------------------------------
@ -1033,7 +1023,7 @@ void CHostFilename::CopyHuman(const BYTE* szHuman)
ASSERT(strlen((const char*)szHuman) < 23);
strcpy((char*)m_szHuman, (const char*)szHuman);
m_bCorrect = TRUE;
m_bCorrect = true;
m_pszHumanLast = m_szHuman + strlen((const char*)m_szHuman);
m_pszHumanExt = SeparateExt(m_szHuman);
}
@ -1079,7 +1069,7 @@ void CHostFilename::SetEntryName()
/// Investigate if the Human68k side name has been processed
//
//---------------------------------------------------------------------------
BOOL CHostFilename::isReduce() const
bool CHostFilename::isReduce() const
{
return strcmp((const char *)m_szHost, (const char*)m_szHuman) != 0;
}
@ -1089,7 +1079,7 @@ BOOL CHostFilename::isReduce() const
/// Evaluate Human68k directory entry attribute
//
//---------------------------------------------------------------------------
BOOL CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
{
BYTE nAttribute = m_dirHuman.attr;
if ((nAttribute & (Human68k::AT_ARCHIVE | Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0)
@ -1228,8 +1218,8 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
ASSERT(pBufLast);
// Compare chars
BOOL bSkip0 = FALSE;
BOOL bSkip1 = FALSE;
bool bSkip0 = false;
bool bSkip1 = false;
for (const BYTE* p = pFirst; p < pLast; p++) {
// Read 1 char
BYTE c = *p;
@ -1238,13 +1228,13 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
d = *pBufFirst++;
// Ajust char for comparison
if (bSkip0 == FALSE) {
if (bSkip1 == FALSE) { // First byte for both c and d
if (!bSkip0) {
if (!bSkip1) { // First byte for both c and d
if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip0 = TRUE;
bSkip0 = true;
}
if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip1 = TRUE;
bSkip1 = true;
}
if (c == d)
continue; // Finishes the evaluation here with high probability
@ -1263,19 +1253,19 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
}
} else { // Only c is first byte
if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip0 = TRUE;
bSkip0 = true;
}
bSkip1 = FALSE;
bSkip1 = false;
}
} else {
if (bSkip1 == FALSE) { // Only d is first byte
bSkip0 = FALSE;
if (!bSkip1) { // Only d is first byte
bSkip0 = false;
if ((0x80 <= d && d <= 0x9F) || 0xE0 <= d) { // Specifically 0x81~0x9F 0xE0~0xEF
bSkip1 = TRUE;
bSkip1 = true;
}
} else { // Second byte for both c and d
bSkip0 = FALSE;
bSkip1 = FALSE;
bSkip0 = false;
bSkip1 = false;
}
}
@ -1297,9 +1287,9 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
/// Compare Human68k side name
//
//---------------------------------------------------------------------------
BOOL CHostPath::isSameHuman(const BYTE* szHuman) const
bool CHostPath::isSameHuman(const BYTE* szHuman) const
{
ASSERT(szHuman);
assert(szHuman);
// Calulate number of chars
size_t nLength = strlen((const char*)m_szHuman);
@ -1307,15 +1297,15 @@ BOOL CHostPath::isSameHuman(const BYTE* szHuman) const
// Check number of chars
if (nLength != n)
return FALSE;
return false;
// Compare Human68k path name
return Compare(m_szHuman, m_szHuman + nLength, szHuman, szHuman + n) == 0;
}
BOOL CHostPath::isSameChild(const BYTE* szHuman) const
bool CHostPath::isSameChild(const BYTE* szHuman) const
{
ASSERT(szHuman);
assert(szHuman);
// Calulate number of chars
size_t nLength = strlen((const char*)m_szHuman);
@ -1323,7 +1313,7 @@ BOOL CHostPath::isSameChild(const BYTE* szHuman) const
// Check number of chars
if (nLength < n)
return FALSE;
return false;
// Compare Human68k path name
return Compare(m_szHuman, m_szHuman + n, szHuman, szHuman + n) == 0;
@ -1459,7 +1449,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
/// Confirm that the file update has been carried out
//
//---------------------------------------------------------------------------
BOOL CHostPath::isRefresh() const
bool CHostPath::isRefresh() const
{
return m_bRefresh;
}
@ -1493,14 +1483,14 @@ void CHostPath::Refresh()
strcpy(szPath, m_szHost);
// Update refresh flag
m_bRefresh = FALSE;
m_bRefresh = false;
// Store previous cache contents
CRing cRingBackup;
m_cRing.InsertRing(&cRingBackup);
// Register file name
BOOL bUpdate = FALSE;
bool bUpdate = false;
dirent **pd = nullptr;
int nument = 0;
int maxent = XM6_HOST_DIRENTRY_FILE_MAX;
@ -1536,7 +1526,7 @@ void CHostPath::Refresh()
for (;;) {
if (pCache == (ring_t*)&cRingBackup) {
pCache = nullptr; // No relevant entry
bUpdate = TRUE; // Confirm new entry
bUpdate = true; // Confirm new entry
pFilename->ConvertHuman();
break;
}
@ -1612,7 +1602,7 @@ void CHostPath::Refresh()
pRing = pCache; // Use previous cache
} else {
Free(pCache); // Remove from the next search target
bUpdate = TRUE; // Flag for update if no match
bUpdate = true; // Flag for update if no match
}
}
@ -1631,14 +1621,13 @@ void CHostPath::Refresh()
// Delete remaining cache
ring_t* p;
while ((p = (ring_t*)cRingBackup.Next()) != (ring_t*)&cRingBackup) {
bUpdate = TRUE; // Confirms the decrease in entries due to deletion
bUpdate = true; // Confirms the decrease in entries due to deletion
Free(p);
}
// Update the identifier if the update has been carried out
if (bUpdate)
m_nId = ++g_nId;
// ASSERT(m_nId);
}
//---------------------------------------------------------------------------
@ -1700,8 +1689,7 @@ void CHostPath::Restore() const
//---------------------------------------------------------------------------
void CHostPath::Release()
{
m_bRefresh = TRUE;
m_bRefresh = true;
}
//===========================================================================
@ -1714,12 +1702,12 @@ CHostEntry::~CHostEntry()
{
Clean();
#ifdef _DEBUG
#ifdef DEBUG
// Confirm object
for (size_t n = 0; n < DRIVE_MAX; n++) {
ASSERT(m_pDrv[n] == nullptr);
for (const auto& d : m_pDrv) {
assert(d == nullptr);
}
#endif // _DEBUG
#endif
}
//---------------------------------------------------------------------------
@ -1729,11 +1717,10 @@ CHostEntry::~CHostEntry()
//---------------------------------------------------------------------------
void CHostEntry::Init() const
{
#ifdef _DEBUG
#ifdef DEBUG
// Confirm object
for (size_t n = 0; n < DRIVE_MAX; n++) {
ASSERT(m_pDrv[n] == nullptr);
for (const auto& d : m_pDrv) {
assert(d == nullptr);
}
#endif
}
@ -1745,11 +1732,10 @@ void CHostEntry::Init() const
//---------------------------------------------------------------------------
void CHostEntry::Clean()
{
// Delete object
for (size_t n = 0; n < DRIVE_MAX; n++) {
delete m_pDrv[n];
m_pDrv[n] = nullptr;
for (auto& d: m_pDrv) {
delete d;
d = nullptr;
}
}
@ -1760,10 +1746,9 @@ void CHostEntry::Clean()
//---------------------------------------------------------------------------
void CHostEntry::CleanCache() const
{
for (size_t i = 0; i < DRIVE_MAX; i++) {
if (m_pDrv[i])
m_pDrv[i]->CleanCache();
for (const auto& d : m_pDrv) {
if (d)
d->CleanCache();
}
CHostPath::InitId();
@ -1829,7 +1814,7 @@ void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
/// Find host side names (path name + file name (can be abbreviated) + attribute)
//
//---------------------------------------------------------------------------
BOOL CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
{
ASSERT(pFiles);
ASSERT(nUnit < DRIVE_MAX);
@ -1856,7 +1841,7 @@ void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
/// Is it write-protected?
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
bool CHostEntry::isWriteProtect(DWORD nUnit) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -1869,7 +1854,7 @@ BOOL CHostEntry::isWriteProtect(DWORD nUnit) const
/// Is it accessible?
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isEnable(DWORD nUnit) const
bool CHostEntry::isEnable(DWORD nUnit) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -1882,7 +1867,7 @@ BOOL CHostEntry::isEnable(DWORD nUnit) const
/// Media check
//
//---------------------------------------------------------------------------
BOOL CHostEntry::isMediaOffline(DWORD nUnit) const
bool CHostEntry::isMediaOffline(DWORD nUnit) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -1921,7 +1906,7 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
/// Media change check
//
//---------------------------------------------------------------------------
BOOL CHostEntry::CheckMedia(DWORD nUnit) const
bool CHostEntry::CheckMedia(DWORD nUnit) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -1960,7 +1945,7 @@ void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
/// Get volume label from cache
//
//---------------------------------------------------------------------------
BOOL CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -1986,7 +1971,7 @@ DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) cons
/// Get cluster size from cache
//
//---------------------------------------------------------------------------
BOOL CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
bool CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
{
ASSERT(nUnit < DRIVE_MAX);
ASSERT(m_pDrv[nUnit]);
@ -2070,7 +2055,7 @@ void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
/// Find file on the Human68k side and create data on the host side
//
//---------------------------------------------------------------------------
BOOL CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
bool CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
{
ASSERT(pEntry);
@ -2249,7 +2234,7 @@ void CHostFilesManager::Free(CHostFiles* pFiles)
/// Set file open mode
//
//---------------------------------------------------------------------------
BOOL CHostFcb::SetMode(DWORD nHumanMode)
bool CHostFcb::SetMode(DWORD nHumanMode)
{
switch (nHumanMode & Human68k::OP_MASK) {
case Human68k::OP_READ:
@ -2262,12 +2247,12 @@ BOOL CHostFcb::SetMode(DWORD nHumanMode)
m_pszMode = "r+b";
break;
default:
return FALSE;
return false;
}
m_bFlag = (nHumanMode & Human68k::OP_SPECIAL) != 0;
return TRUE;
return true;
}
void CHostFcb::SetFilename(const TCHAR* szFilename)
@ -2290,20 +2275,20 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
//
/// Create file
///
/// Return FALSE if error is thrown.
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Create(DWORD, BOOL bForce)
bool CHostFcb::Create(DWORD, bool bForce)
{
ASSERT((Human68k::AT_DIRECTORY | Human68k::AT_VOLUME) == 0);
ASSERT(strlen(m_szFilename) > 0);
ASSERT(m_pFile == nullptr);
// Duplication check
if (bForce == FALSE) {
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)
return FALSE;
return false;
}
// Create file
@ -2316,16 +2301,16 @@ BOOL CHostFcb::Create(DWORD, BOOL bForce)
//
/// File open
///
/// Return FALSE if error is thrown.
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Open()
bool CHostFcb::Open()
{
ASSERT(strlen(m_szFilename) > 0);
// Fail if directory
if (struct stat st; stat(S2U(m_szFilename), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR)) {
return FALSE || m_bFlag;
return false || m_bFlag;
}
// File open
@ -2335,23 +2320,6 @@ BOOL CHostFcb::Open()
return m_pFile != nullptr || m_bFlag;
}
//---------------------------------------------------------------------------
//
/// File seek
///
/// Return FALSE if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Rewind(DWORD nOffset) const
{
ASSERT(m_pFile);
if (fseek(m_pFile, nOffset, SEEK_SET))
return FALSE;
return ftell(m_pFile) != -1L;
}
//---------------------------------------------------------------------------
//
/// Read file
@ -2396,10 +2364,10 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
//
/// Truncate file
///
/// Return FALSE if error is thrown.
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Truncate() const
bool CHostFcb::Truncate() const
{
ASSERT(m_pFile);
@ -2442,10 +2410,10 @@ DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
//
/// Set file time stamp
///
/// Return FALSE if error is thrown.
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
bool CHostFcb::TimeStamp(DWORD nHumanTime) const
{
ASSERT(m_pFile || m_bFlag);
@ -2458,7 +2426,7 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
t.tm_sec = (nHumanTime & 31) << 1;
time_t ti = mktime(&t);
if (ti == (time_t)-1)
return FALSE;
return false;
utimbuf ut;
ut.actime = ti;
ut.modtime = ti;
@ -2474,21 +2442,17 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime) const
//
/// File close
///
/// Return FALSE if error is thrown.
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Close()
void CHostFcb::Close()
{
BOOL bResult = TRUE;
// File close
// Always initialize because of the Close→Free (internally one more Close) flow.
if (m_pFile) {
fclose(m_pFile);
m_pFile = nullptr;
}
return bResult;
}
//===========================================================================
@ -2547,8 +2511,8 @@ CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
auto p = (ring_t*)m_cRing.Prev();
// Error if in use (just in case)
if (p->f.isSameKey(0) == FALSE) {
ASSERT(FALSE);
if (!p->f.isSameKey(0)) {
ASSERT(false);
return nullptr;
}
@ -2711,7 +2675,7 @@ int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
if (f.isRootPath())
return 0;
f.SetPathOnly();
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_DIRNOTFND;
return 0;
@ -2745,7 +2709,7 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
CHostFiles f;
f.SetPath(pNamests);
f.SetPathOnly();
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_INVALIDPATH;
f.AddFilename();
@ -2787,7 +2751,7 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_DIRECTORY);
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_DIRNOTFND;
// Delete cache
@ -2837,13 +2801,13 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_FILENOTFND;
CHostFiles fNew;
fNew.SetPath(pNamestsNew);
fNew.SetPathOnly();
if (fNew.Find(nUnit, &m_cEntry) == FALSE)
if (!fNew.Find(nUnit, &m_cEntry))
return FS_INVALIDPATH;
fNew.AddFilename();
@ -2894,7 +2858,7 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
// Generate path name
CHostFiles f;
f.SetPath(pNamests);
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_FILENOTFND;
// Delete file
@ -2930,7 +2894,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_FILENOTFND;
// Exit if attribute is acquired
@ -2966,7 +2930,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
m_cEntry.CleanCache(nUnit, f.GetHumanPath());
// Get attribute after changing
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_FILENOTFND;
return f.GetAttribute();
@ -3006,11 +2970,11 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
// Path check
CHostFiles f;
f.SetPath(pNamests);
if (f.isRootPath() == FALSE)
if (!f.isRootPath())
return FS_FILENOTFND;
// Immediately return the results without allocating buffer
if (FilesVolume(nUnit, pFiles) == FALSE)
if (!FilesVolume(nUnit, pFiles))
return FS_FILENOTFND;
return 0;
}
@ -3026,9 +2990,9 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
// Directory check
pHostFiles->SetPath(pNamests);
if (pHostFiles->isRootPath() == FALSE) {
if (!pHostFiles->isRootPath()) {
pHostFiles->SetPathOnly();
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
m_cFiles.Free(pHostFiles);
return FS_DIRNOTFND;
}
@ -3039,7 +3003,7 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
pHostFiles->SetAttribute(pFiles->fatr);
// Find file
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
m_cFiles.Free(pHostFiles);
return FS_FILENOTFND;
}
@ -3055,12 +3019,6 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
pFiles->sector = nKey;
pFiles->offset = 0;
// When the file name does not include wildcards, the buffer may be released
if (pNamests->wildcard == 0) {
// However, there is a chance the virtual selector may be used for emulation, so don't release immediately
// m_cFiles.Free(pHostFiles);
}
return 0;
}
@ -3090,7 +3048,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
return FS_INVALIDPTR;
// Find file
if (pHostFiles->Find(nUnit, &m_cEntry) == FALSE) {
if (!pHostFiles->Find(nUnit, &m_cEntry)) {
m_cFiles.Free(pHostFiles);
return FS_FILENOTFND;
}
@ -3113,7 +3071,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
/// $49 - Create new file
//
//---------------------------------------------------------------------------
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce)
{
ASSERT(pNamests);
ASSERT(nKey);
@ -3142,7 +3100,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
CHostFiles f;
f.SetPath(pNamests);
f.SetPathOnly();
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_INVALIDPATH;
f.AddFilename();
@ -3159,13 +3117,13 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
// Set open mode
pFcb->mode = (WORD)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
if (!pHostFcb->SetMode(pFcb->mode)) {
m_cFcb.Free(pHostFcb);
return FS_ILLEGALMOD;
}
// Create file
if (pHostFcb->Create(nHumanAttribute, bForce) == FALSE) {
if (!pHostFcb->Create(nHumanAttribute, bForce)) {
m_cFcb.Free(pHostFcb);
return FS_FILEEXIST;
}
@ -3215,7 +3173,7 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
CHostFiles f;
f.SetPath(pNamests);
f.SetAttribute(Human68k::AT_ALL);
if (f.Find(nUnit, &m_cEntry) == FALSE)
if (!f.Find(nUnit, &m_cEntry))
return FS_FILENOTFND;
// Time stamp
@ -3233,13 +3191,13 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
pHostFcb->SetHumanPath(f.GetHumanPath());
// Set open mode
if (pHostFcb->SetMode(pFcb->mode) == FALSE) {
if (!pHostFcb->SetMode(pFcb->mode)) {
m_cFcb.Free(pHostFcb);
return FS_ILLEGALMOD;
}
// File open
if (pHostFcb->Open() == FALSE) {
if (!pHostFcb->Open()) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPATH;
}
@ -3345,7 +3303,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
DWORD nResult;
if (nSize == 0) {
// Truncate
if (pHostFcb->Truncate() == FALSE) {
if (!pHostFcb->Truncate()) {
m_cFcb.Free(pHostFcb);
return FS_CANTSEEK;
}
@ -3453,7 +3411,7 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
return FS_NOTOPENED;
// Set time stamp
if (pHostFcb->TimeStamp(nHumanTime) == FALSE) {
if (!pHostFcb->TimeStamp(nHumanTime)) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPRM;
}
@ -3552,9 +3510,9 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
media = m_cEntry.GetMediaByte(nUnit);
// Acquire sector data
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
if (!m_cEntry.GetCapacityCache(nUnit, &cap)) {
// Carry out an extra media check here because it may be skipped when doing a manual eject
if (m_cEntry.isEnable(nUnit) == FALSE)
if (!m_cEntry.isEnable(nUnit))
goto none;
// Media check
@ -3638,7 +3596,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
// Acquire sector data
Human68k::capacity_t cap;
if (m_cEntry.GetCapacityCache(nUnit, &cap) == FALSE) {
if (!m_cEntry.GetCapacityCache(nUnit, &cap)) {
// Get drive status
m_cEntry.GetCapacity(nUnit, &cap);
}
@ -3680,7 +3638,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
CHostFcb f;
f.SetFilename(pHostFiles->GetPath());
f.SetMode(Human68k::OP_READ);
if (f.Open() == FALSE)
if (!f.Open())
return FS_INVALIDPRM;
memset(pBuffer, 0, 0x200);
DWORD nResult = f.Read(pBuffer, 0x200);
@ -3793,7 +3751,6 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
//---------------------------------------------------------------------------
int CFileSys::Flush(DWORD nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
return FS_FATAL_INVALIDUNIT;
@ -3811,7 +3768,6 @@ int CFileSys::Flush(DWORD nUnit) const
//---------------------------------------------------------------------------
int CFileSys::CheckMedia(DWORD nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
return FS_FATAL_INVALIDUNIT;
@ -3820,7 +3776,7 @@ int CFileSys::CheckMedia(DWORD nUnit) const
// Media change check
// Throw error when media is not inserted
if (BOOL bResult = m_cEntry.CheckMedia(nUnit); bResult == FALSE) {
if (!m_cEntry.CheckMedia(nUnit)) {
return FS_INVALIDFUNC;
}
@ -3834,7 +3790,6 @@ int CFileSys::CheckMedia(DWORD nUnit) const
//---------------------------------------------------------------------------
int CFileSys::Lock(DWORD nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
return FS_FATAL_INVALIDUNIT;
@ -3857,7 +3812,6 @@ int CFileSys::Lock(DWORD nUnit) const
//---------------------------------------------------------------------------
void CFileSys::SetOption(DWORD nOption)
{
// Clear cache when option settings change
if (m_nOption ^ nOption)
m_cEntry.CleanCache();
@ -3957,26 +3911,26 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
/// Get volume label
//
//---------------------------------------------------------------------------
BOOL CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
bool CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
{
ASSERT(pFiles);
// Get volume label
TCHAR szVolume[32];
if (BOOL bResult = m_cEntry.GetVolumeCache(nUnit, szVolume); bResult == FALSE) {
if (bool bResult = m_cEntry.GetVolumeCache(nUnit, szVolume); !bResult) {
// Carry out an extra media check here because it may be skipped when doing a manual eject
if (m_cEntry.isEnable(nUnit) == FALSE)
return FALSE;
if (!m_cEntry.isEnable(nUnit))
return false;
// Media check
if (m_cEntry.isMediaOffline(nUnit))
return FALSE;
return false;
// Get volume label
m_cEntry.GetVolume(nUnit, szVolume);
}
if (szVolume[0] == _T('\0'))
return FALSE;
return false;
pFiles->attr = Human68k::AT_VOLUME;
pFiles->time = 0;
@ -3988,5 +3942,5 @@ BOOL CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
fname.ConvertHuman();
strcpy((char*)pFiles->full, (const char*)fname.GetHuman());
return TRUE;
return true;
}

View File

@ -451,8 +451,8 @@ public:
const TCHAR* GetHost() const { return m_szHost; } ///< Get the name of the host
void ConvertHuman(int nCount = -1); ///< Convert the Human68k name
void CopyHuman(const BYTE* szHuman); ///< Copy the Human68k name
BOOL isReduce() const; ///< Inspect if the Human68k name is generated
BOOL isCorrect() const { return m_bCorrect; } ///< Inspect if the Human68k file name adhers to naming rules
bool isReduce() const; ///< Inspect if the Human68k name is generated
bool isCorrect() const { return m_bCorrect; } ///< Inspect if the Human68k file name adhers to naming rules
const BYTE* GetHuman() const { return m_szHuman; } ///< Get Human68k file name
const BYTE* GetHumanLast() const
{ return m_pszHumanLast; } ///< Get Human68k file name
@ -470,9 +470,9 @@ public:
{ m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
const Human68k::dirent_t* GetEntry() const
{ return &m_dirHuman; } ///< Get Human68k directory entry
BOOL CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
BOOL isSameEntry(const Human68k::dirent_t* pdirHuman) const
{ ASSERT(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
int CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
bool isSameEntry(const Human68k::dirent_t* pdirHuman) const
{ assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
///< Determine Human68k directory entry match
// Path name operations
@ -484,7 +484,7 @@ private:
const BYTE* m_pszHumanLast = nullptr; ///< Last position of the Human68k internal name of the relevant entry
const BYTE* m_pszHumanExt = nullptr; ///< Position of the extension of the Human68k internal name of the relevant entry
BOOL m_bCorrect = FALSE; ///< TRUE if the relevant entry of the Human68k internal name is correct
bool m_bCorrect = false; ///< TRUE if the relevant entry of the Human68k internal name is correct
BYTE m_szHuman[24]; ///< Human68k internal name of the relevant entry
Human68k::dirent_t m_dirHuman; ///< All information for the Human68k relevant entry
TCHAR m_szHost[FILEPATH_MAX]; ///< The host name of the relevant entry (variable length)
@ -535,35 +535,35 @@ public:
CHostPath(CHostPath&) = delete;
CHostPath& operator=(const CHostPath&) = delete;
void Clean(); ///< Initialialize for reuse
void Clean(); ///< Initialialize for reuse
void SetHuman(const BYTE* szHuman); ///< Directly specify the name on the Human68k side
void SetHost(const TCHAR* szHost); ///< Directly specify the name on the host side
BOOL isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
BOOL isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
void SetHuman(const BYTE* szHuman); ///< Directly specify the name on the Human68k side
void SetHost(const TCHAR* szHost); ///< Directly specify the name on the host side
bool isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
bool isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
///< Find file name
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
///< Find file name (with support for wildcards)
BOOL isRefresh() const; ///< Check that the file change has been done
void Refresh(); ///< Refresh file
void Backup(); /// Backup the time stamp on the host side
void Restore() const; /// Restore the time stamp on the host side
void Release(); ///< Update
bool isRefresh() const; ///< Check that the file change has been done
void Refresh(); ///< Refresh file
void Backup(); /// Backup the time stamp on the host side
void Restore() const; /// Restore the time stamp on the host side
void Release(); ///< Update
// CHostEntry is an external API that we use
static void InitId() { g_nId = 0; } ///< Initialize the counter for the unique ID generation
static void InitId() { g_nId = 0; } ///< Initialize the counter for the unique ID generation
private:
static ring_t* Alloc(size_t nLength); ///< Allocate memory for the file name
static void Free(ring_t* pRing); ///< Release memory for the file name
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
static ring_t* Alloc(size_t nLength); ///< Allocate memory for the file name
static void Free(ring_t* pRing); ///< Release memory for the file name
static int Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFirst, const BYTE* pBufLast);
///< Compare string (with support for wildcards)
CRing m_cRing; ///< For CHostFilename linking
time_t m_tBackup = FALSE; ///< For time stamp restoration
BOOL m_bRefresh = TRUE; ///< Refresh flag
time_t m_tBackup = 0; ///< For time stamp restoration
bool m_bRefresh = true; ///< Refresh flag
DWORD m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< The internal Human68k name for the relevant entry
TCHAR m_szHost[FILEPATH_MAX]; ///< The host side name for the relevant entry
@ -602,14 +602,14 @@ public:
void Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetPath(const Human68k::namests_t* pNamests); ///< Create path and file name internally
BOOL isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
bool isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
BOOL isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
bool isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
void SetAttribute(DWORD nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
BOOL Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
bool Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
const CHostFilename* Find(const CHostPath* pPath); ///< Find file name
void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
void SetResult(const TCHAR* szPath); ///< Set names on the host side
@ -681,27 +681,26 @@ public:
void Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
BOOL isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetUpdate() { m_bUpdate = TRUE; } ///< Update
BOOL isUpdate() const { return m_bUpdate; } ///< Get update state
BOOL SetMode(DWORD nHumanMode); ///< Set file open mode
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetUpdate() { m_bUpdate = true; } ///< Update
bool isUpdate() const { return m_bUpdate; } ///< Get update state
bool SetMode(DWORD nHumanMode); ///< Set file open mode
void SetFilename(const TCHAR* szFilename); ///< Set file name
void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
BOOL Create(DWORD nHumanAttribute, BOOL bForce); ///< Create file
BOOL Open(); ///< Open file
BOOL Rewind(DWORD nOffset) const; ///< Seek file
bool Create(DWORD nHumanAttribute, bool bForce); ///< Create file
bool Open(); ///< Open file
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file
BOOL Truncate() const; ///< Truncate file
bool Truncate() const; ///< Truncate file
DWORD Seek(DWORD nOffset, DWORD nHumanSeek); ///< Seek file
BOOL TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
BOOL Close(); ///< Close file
bool TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
void Close(); ///< Close file
private:
DWORD m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
BOOL m_bUpdate = FALSE; ///< Update flag
bool m_bUpdate = false; ///< Update flag
FILE* m_pFile = nullptr; ///< Host side file object
const char* m_pszMode = nullptr; ///< Host side file open mode
bool m_bFlag = false; ///< Host side file open flag
@ -753,19 +752,19 @@ public:
void Init(const TCHAR* szBase, DWORD nFlag); ///< Initialization (device startup and load)
BOOL isWriteProtect() const { return m_bWriteProtect; }
BOOL isEnable() const { return m_bEnable; } ///< Is it accessible?
BOOL isMediaOffline() const;
bool isWriteProtect() const { return m_bWriteProtect; }
bool isEnable() const { return m_bEnable; } ///< Is it accessible?
bool isMediaOffline() const;
BYTE GetMediaByte() const;
DWORD GetStatus() const;
void SetEnable(BOOL bEnable); ///< Set media status
BOOL CheckMedia(); ///< Check if media was changed
void SetEnable(bool); ///< Set media status
bool CheckMedia(); ///< Check if media was changed
void Update(); ///< Update media status
void Eject();
void GetVolume(TCHAR* szLabel); ///< Get volume label
BOOL GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
bool GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
DWORD GetCapacity(Human68k::capacity_t* pCapacity);
BOOL GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
bool GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
// Cache operations
void CleanCache() const; ///< Update all cache
@ -775,7 +774,7 @@ public:
CHostPath* FindCache(const BYTE* szHuman); ///< Inspect if the specified path is cached
CHostPath* CopyCache(CHostFiles* pFiles); ///< Acquire the host side name on the basis of cache information
CHostPath* MakeCache(CHostFiles* pFiles); ///< Get all required data to construct a host side name
BOOL Find(CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
bool Find(CHostFiles* pFiles); ///< Find host side name (path + file name (can be abbreviated) + attribute)
private:
// Path name operations
@ -788,12 +787,12 @@ private:
CHostPath f;
};
BOOL m_bWriteProtect = FALSE; ///< TRUE if write-protected
BOOL m_bEnable = FALSE; ///< TRUE if media is usable
bool m_bWriteProtect = false; ///< TRUE if write-protected
bool m_bEnable = false; ///< TRUE if media is usable
DWORD m_nRing = 0; ///< Number of stored path names
CRing m_cRing; ///< For attaching to CHostPath
Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached
BOOL m_bVolumeCache = FALSE; ///< TRUE if the volume label has been read
bool m_bVolumeCache = false; ///< TRUE if the volume label has been read
TCHAR m_szVolumeCache[24] = {}; ///< Volume label cache
TCHAR m_szBase[FILEPATH_MAX] = {}; ///< Base path
};
@ -824,22 +823,22 @@ public:
void CleanCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
void DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
BOOL Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
bool Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
// Drive object operations
void SetDrv(DWORD nUnit, CHostDrv* pDrv);
BOOL isWriteProtect(DWORD nUnit) const;
BOOL isEnable(DWORD nUnit) const; ///< Is it accessible?
BOOL isMediaOffline(DWORD nUnit) const;
bool isWriteProtect(DWORD nUnit) const;
bool isEnable(DWORD nUnit) const; ///< Is it accessible?
bool isMediaOffline(DWORD nUnit) const;
BYTE GetMediaByte(DWORD nUnit) const;
DWORD GetStatus(DWORD nUnit) const; ///< Get drive status
BOOL CheckMedia(DWORD nUnit) const; ///< Media change check
bool CheckMedia(DWORD nUnit) const; ///< Media change check
void Eject(DWORD nUnit) const;
void GetVolume(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label
BOOL GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
bool GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
BOOL GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
bool GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
private:
@ -900,7 +899,7 @@ public:
int Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
///< $47 - Find file
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce);
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce);
///< $49 - Create file
int Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
///< $4A - Open file
@ -927,13 +926,11 @@ public:
DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options
static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option
enum {
DriveMax = CHostEntry::DRIVE_MAX ///< Max number of drive candidates
};
static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates
private:
void InitOption(const Human68k::argument_t* pArgument);
BOOL FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
void InitOption(const Human68k::argument_t* pArgument);
bool FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
DWORD m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)

View File

@ -25,8 +25,6 @@
#include "rascsi_exceptions.h"
#include <sstream>
static const char *BRIDGE_NAME = "rascsi_bridge";
using namespace std;
using namespace ras_util;
@ -39,7 +37,7 @@ static bool br_setif(int br_socket_fd, const char* bridgename, const char* ifnam
struct ifreq ifr;
ifr.ifr_ifindex = if_nametoindex(ifname);
if (ifr.ifr_ifindex == 0) {
LOGERROR("Can't if_nametoindex: %s", strerror(errno))
LOGERROR("Can't if_nametoindex %s: %s", ifname, strerror(errno))
return false;
}
strncpy(ifr.ifr_name, bridgename, IFNAMSIZ - 1);
@ -118,14 +116,14 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
return false;
}
LOGTRACE("Opened tap device %d",m_hTAP)
LOGTRACE("Opened tap device %d", m_hTAP)
// IFF_NO_PI for no extra packet information
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
char dev[IFNAMSIZ] = "ras0";
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
string dev = "ras0";
strncpy(ifr.ifr_name, dev.c_str(), IFNAMSIZ - 1);
LOGTRACE("Going to open %s", ifr.ifr_name)
@ -325,7 +323,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
LOGTRACE("Got the MAC")
// Save MAC address
memcpy(m_MacAddr, ifr.ifr_hwaddr.sa_data, sizeof(m_MacAddr));
memcpy(m_MacAddr.data(), ifr.ifr_hwaddr.sa_data, m_MacAddr.size());
close(ip_fd);
close(br_socket_fd);
@ -403,7 +401,8 @@ void CTapDriver::Flush()
{
LOGTRACE("%s", __PRETTY_FUNCTION__)
while(PendingPackets()){
(void)Rx(m_garbage_buffer);
array<BYTE, ETH_FRAME_LEN> m_garbage_buffer;
(void)Rx(m_garbage_buffer.data());
}
}
@ -411,7 +410,7 @@ void CTapDriver::GetMacAddr(BYTE *mac) const
{
ASSERT(mac);
memcpy(mac, m_MacAddr, sizeof(m_MacAddr));
memcpy(mac, m_MacAddr.data(), m_MacAddr.size());
}
//---------------------------------------------------------------------------

View File

@ -18,6 +18,7 @@
#include <unordered_map>
#include <list>
#include <string>
#include <array>
#ifndef ETH_FRAME_LEN
#define ETH_FRAME_LEN 1514
@ -32,11 +33,11 @@ using namespace std;
//===========================================================================
class CTapDriver
{
private:
friend class SCSIDaynaPort;
friend class SCSIBR;
static constexpr const char *BRIDGE_NAME = "rascsi_bridge";
CTapDriver() = default;
~CTapDriver() = default;
CTapDriver(CTapDriver&) = delete;
@ -58,10 +59,8 @@ public:
void Flush(); // Purge all of the packets that are waiting to be processed
private:
BYTE m_MacAddr[6] = {}; // MAC Address
int m_hTAP = -1; // File handle
BYTE m_garbage_buffer[ETH_FRAME_LEN];
array<byte, 6> m_MacAddr; // MAC Address
int m_hTAP = -1; // File handle
pcap_t *m_pcap = nullptr;
pcap_dumper_t *m_pcap_dumper = nullptr;

View File

@ -13,14 +13,17 @@
#include "log.h"
#include "rascsi_exceptions.h"
#include "device.h"
#include <iomanip>
using namespace std;
Device::Device(const string& t) : type(t)
{
assert(type.length() == 4);
char rev[5];
sprintf(rev, "%02d%02d", rascsi_major_version, rascsi_minor_version);
revision = rev;
ostringstream os;
os << setw(2) << setfill('0') << rascsi_major_version << setw(2) << setfill('0') << rascsi_minor_version;
revision = os.str();
}
void Device::Reset()

View File

@ -71,7 +71,7 @@ class Device
// Sense Key
// Additional Sense Code (ASC)
// LSB Additional Sense Code Qualifier(ASCQ)
int status_code = scsi_defs::status::GOOD;
int status_code = 0;
protected:
@ -97,7 +97,7 @@ public:
// Override for device specific initializations, to be called after all device properties have been set
virtual bool Init(const unordered_map<string, string>&) { return true; };
virtual bool Dispatch() = 0;
virtual bool Dispatch(scsi_defs::scsi_command) = 0;
const string& GetType() const { return type; }

View File

@ -74,9 +74,8 @@ DeviceFactory& DeviceFactory::instance()
void DeviceFactory::DeleteDevice(const PrimaryDevice *device) const
{
auto iterpair = devices.equal_range(device->GetId());
for (auto it = iterpair.first; it != iterpair.second; ++it) {
auto [begin, end] = devices.equal_range(device->GetId());
for (auto it = begin; it != end; ++it) {
if (it->second->GetLun() == device->GetLun()) {
devices.erase(it);
@ -219,7 +218,7 @@ PrimaryDevice *DeviceFactory::CreateDevice(PbDeviceType type, const string& file
break;
case SCHS:
device = make_unique<HostServices>();
device = make_unique<HostServices>(this);
// Since this is an emulation for a specific device the full INQUIRY data have to be set accordingly
device->SetVendor("RaSCSI");
device->SetProduct("Host Services");
@ -264,9 +263,9 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
{
list<string> network_interfaces;
struct ifaddrs *addrs;
ifaddrs *addrs;
getifaddrs(&addrs);
struct ifaddrs *tmp = addrs;
ifaddrs *tmp = addrs;
while (tmp) {
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET &&
@ -276,7 +275,7 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
ifreq ifr = {};
strcpy(ifr.ifr_name, tmp->ifa_name);
// Only list interfaces that are up
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && ifr.ifr_flags & IFF_UP) {
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
network_interfaces.emplace_back(tmp->ifa_name);
}

View File

@ -25,34 +25,34 @@ using namespace scsi_defs;
Disk::Disk(const string& id) : ModePageDevice(id), ScsiBlockCommands()
{
dispatcher.AddCommand(eCmdRezero, "Rezero", &Disk::Rezero);
dispatcher.AddCommand(eCmdFormat, "FormatUnit", &Disk::FormatUnit);
dispatcher.AddCommand(eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
dispatcher.AddCommand(eCmdRead6, "Read6", &Disk::Read6);
dispatcher.AddCommand(eCmdWrite6, "Write6", &Disk::Write6);
dispatcher.AddCommand(eCmdSeek6, "Seek6", &Disk::Seek6);
dispatcher.AddCommand(eCmdReserve6, "Reserve6", &Disk::Reserve);
dispatcher.AddCommand(eCmdRelease6, "Release6", &Disk::Release);
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
dispatcher.AddCommand(eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
dispatcher.AddCommand(eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
dispatcher.AddCommand(eCmdRead10, "Read10", &Disk::Read10);
dispatcher.AddCommand(eCmdWrite10, "Write10", &Disk::Write10);
dispatcher.AddCommand(eCmdReadLong10, "ReadLong10", &Disk::ReadWriteLong10);
dispatcher.AddCommand(eCmdWriteLong10, "WriteLong10", &Disk::ReadWriteLong10);
dispatcher.AddCommand(eCmdWriteLong16, "WriteLong16", &Disk::ReadWriteLong16);
dispatcher.AddCommand(eCmdSeek10, "Seek10", &Disk::Seek10);
dispatcher.AddCommand(eCmdVerify10, "Verify10", &Disk::Verify10);
dispatcher.AddCommand(eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
dispatcher.AddCommand(eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
dispatcher.AddCommand(eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
dispatcher.AddCommand(eCmdReserve10, "Reserve10", &Disk::Reserve);
dispatcher.AddCommand(eCmdRelease10, "Release10", &Disk::Release);
dispatcher.AddCommand(eCmdRead16, "Read16", &Disk::Read16);
dispatcher.AddCommand(eCmdWrite16, "Write16", &Disk::Write16);
dispatcher.AddCommand(eCmdVerify16, "Verify16", &Disk::Verify16);
dispatcher.AddCommand(eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero);
dispatcher.Add(scsi_command::eCmdFormat, "FormatUnit", &Disk::FormatUnit);
dispatcher.Add(scsi_command::eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
dispatcher.Add(scsi_command::eCmdRead6, "Read6", &Disk::Read6);
dispatcher.Add(scsi_command::eCmdWrite6, "Write6", &Disk::Write6);
dispatcher.Add(scsi_command::eCmdSeek6, "Seek6", &Disk::Seek6);
dispatcher.Add(scsi_command::eCmdReserve6, "Reserve6", &Disk::Reserve);
dispatcher.Add(scsi_command::eCmdRelease6, "Release6", &Disk::Release);
dispatcher.Add(scsi_command::eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
dispatcher.Add(scsi_command::eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
dispatcher.Add(scsi_command::eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
dispatcher.Add(scsi_command::eCmdRead10, "Read10", &Disk::Read10);
dispatcher.Add(scsi_command::eCmdWrite10, "Write10", &Disk::Write10);
dispatcher.Add(scsi_command::eCmdReadLong10, "ReadLong10", &Disk::ReadWriteLong10);
dispatcher.Add(scsi_command::eCmdWriteLong10, "WriteLong10", &Disk::ReadWriteLong10);
dispatcher.Add(scsi_command::eCmdWriteLong16, "WriteLong16", &Disk::ReadWriteLong16);
dispatcher.Add(scsi_command::eCmdSeek10, "Seek10", &Disk::Seek10);
dispatcher.Add(scsi_command::eCmdVerify10, "Verify10", &Disk::Verify10);
dispatcher.Add(scsi_command::eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
dispatcher.Add(scsi_command::eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
dispatcher.Add(scsi_command::eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
dispatcher.Add(scsi_command::eCmdReserve10, "Reserve10", &Disk::Reserve);
dispatcher.Add(scsi_command::eCmdRelease10, "Release10", &Disk::Release);
dispatcher.Add(scsi_command::eCmdRead16, "Read16", &Disk::Read16);
dispatcher.Add(scsi_command::eCmdWrite16, "Write16", &Disk::Write16);
dispatcher.Add(scsi_command::eCmdVerify16, "Verify16", &Disk::Verify16);
dispatcher.Add(scsi_command::eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
}
Disk::~Disk()
@ -65,7 +65,7 @@ Disk::~Disk()
delete disk.dcache;
}
bool Disk::Dispatch()
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) {
@ -77,7 +77,7 @@ bool Disk::Dispatch()
}
// The superclass handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
//---------------------------------------------------------------------------
@ -94,10 +94,10 @@ void Disk::Open(const Filepath& path)
// Cache initialization
assert (!disk.dcache);
disk.dcache = new DiskCache(path, disk.size, disk.blocks, disk.image_offset);
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::ReadWrite)) {
if (Fileio fio; fio.Open(path, Fileio::OpenMode::ReadWrite)) {
// Write permission
fio.Close();
} else {
@ -141,7 +141,7 @@ void Disk::Read(access_mode mode)
uint64_t start;
if (CheckAndGetStartAndCount(start, ctrl->blocks, mode)) {
ctrl->length = Read(ctrl->cmd, ctrl->buffer, start);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length)
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
// Set next block
ctrl->next = start + 1;
@ -332,10 +332,10 @@ bool Disk::Eject(bool force)
return status;
}
int Disk::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
int Disk::ModeSense6(const vector<int>& cdb, BYTE *buf, int max_length) const
{
// Get length, clear buffer
auto length = (int)cdb[4];
auto length = cdb[4];
if (length > max_length) {
length = max_length;
}
@ -385,7 +385,7 @@ int Disk::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
return size;
}
int Disk::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
int Disk::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
{
// Get length, clear buffer
int length = (cdb[7] << 8) | cdb[8];
@ -397,56 +397,53 @@ int Disk::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
// Basic Information
int size = 8;
// Add block descriptor if DBD is 0
if ((cdb[1] & 0x08) == 0) {
// Only if ready
if (IsReady()) {
uint64_t disk_blocks = GetBlockCount();
uint32_t disk_size = GetSectorSizeInBytes();
// Add block descriptor if DBD is 0, only if ready
if ((cdb[1] & 0x08) == 0 && IsReady()) {
uint64_t disk_blocks = GetBlockCount();
uint32_t disk_size = GetSectorSizeInBytes();
// Check LLBAA for short or long block descriptor
if ((cdb[1] & 0x10) == 0 || disk_blocks <= 0xFFFFFFFF) {
// Mode parameter header, block descriptor length
buf[7] = 0x08;
// Check LLBAA for short or long block descriptor
if ((cdb[1] & 0x10) == 0 || disk_blocks <= 0xFFFFFFFF) {
// Mode parameter header, block descriptor length
buf[7] = 0x08;
// Short LBA mode parameter block descriptor (number of blocks and block length)
// Short LBA mode parameter block descriptor (number of blocks and block length)
buf[8] = (BYTE)(disk_blocks >> 24);
buf[9] = (BYTE)(disk_blocks >> 16);
buf[10] = (BYTE)(disk_blocks >> 8);
buf[11] = (BYTE)disk_blocks;
buf[8] = (BYTE)(disk_blocks >> 24);
buf[9] = (BYTE)(disk_blocks >> 16);
buf[10] = (BYTE)(disk_blocks >> 8);
buf[11] = (BYTE)disk_blocks;
buf[13] = (BYTE)(disk_size >> 16);
buf[14] = (BYTE)(disk_size >> 8);
buf[15] = (BYTE)disk_size;
buf[13] = (BYTE)(disk_size >> 16);
buf[14] = (BYTE)(disk_size >> 8);
buf[15] = (BYTE)disk_size;
size = 16;
}
else {
// Mode parameter header, LONGLBA
buf[4] = 0x01;
size = 16;
}
else {
// Mode parameter header, LONGLBA
buf[4] = 0x01;
// Mode parameter header, block descriptor length
buf[7] = 0x10;
// Mode parameter header, block descriptor length
buf[7] = 0x10;
// Long LBA mode parameter block descriptor (number of blocks and block length)
// Long LBA mode parameter block descriptor (number of blocks and block length)
buf[8] = (BYTE)(disk_blocks >> 56);
buf[9] = (BYTE)(disk_blocks >> 48);
buf[10] = (BYTE)(disk_blocks >> 40);
buf[11] = (BYTE)(disk_blocks >> 32);
buf[12] = (BYTE)(disk_blocks >> 24);
buf[13] = (BYTE)(disk_blocks >> 16);
buf[14] = (BYTE)(disk_blocks >> 8);
buf[15] = (BYTE)disk_blocks;
buf[8] = (BYTE)(disk_blocks >> 56);
buf[9] = (BYTE)(disk_blocks >> 48);
buf[10] = (BYTE)(disk_blocks >> 40);
buf[11] = (BYTE)(disk_blocks >> 32);
buf[12] = (BYTE)(disk_blocks >> 24);
buf[13] = (BYTE)(disk_blocks >> 16);
buf[14] = (BYTE)(disk_blocks >> 8);
buf[15] = (BYTE)disk_blocks;
buf[20] = (BYTE)(disk_size >> 24);
buf[21] = (BYTE)(disk_size >> 16);
buf[22] = (BYTE)(disk_size >> 8);
buf[23] = (BYTE)disk_size;
buf[20] = (BYTE)(disk_size >> 24);
buf[21] = (BYTE)(disk_size >> 16);
buf[22] = (BYTE)(disk_size >> 8);
buf[23] = (BYTE)disk_size;
size = 24;
}
size = 24;
}
}
@ -475,7 +472,7 @@ void Disk::SetDeviceParameters(BYTE *buf) const
}
}
void Disk::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void Disk::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
{
// Page code 1 (read-write error recovery)
if (page == 0x01 || page == 0x3f) {
@ -501,18 +498,18 @@ void Disk::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable
AddVendorPage(pages, page, changeable);
}
void Disk::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
void Disk::AddErrorPage(map<int, vector<byte>>& pages, bool) const
{
vector<BYTE> buf(12);
vector<byte> buf(12);
// Retry count is 0, limit time uses internal default value
pages[1] = buf;
}
void Disk::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
void Disk::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(24);
vector<byte> buf(24);
// No changeable area
if (changeable) {
@ -523,41 +520,41 @@ void Disk::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
if (IsReady()) {
// Set the number of tracks in one zone to 8
buf[0x03] = 0x08;
buf[0x03] = (byte)0x08;
// Set sector/track to 25
buf[0x0a] = 0x00;
buf[0x0b] = 0x19;
buf[0x0a] = (byte)0x00;
buf[0x0b] = (byte)0x19;
// Set the number of bytes in the physical sector
int size = 1 << disk.size;
buf[0x0c] = (BYTE)(size >> 8);
buf[0x0d] = (BYTE)size;
buf[0x0c] = (byte)(size >> 8);
buf[0x0d] = (byte)size;
// Interleave 1
buf[0x0e] = 0x00;
buf[0x0f] = 0x01;
buf[0x0e] = (byte)0x00;
buf[0x0f] = (byte)0x01;
// Track skew factor 11
buf[0x10] = 0x00;
buf[0x11] = 0x0b;
buf[0x10] = (byte)0x00;
buf[0x11] = (byte)0x0b;
// Cylinder skew factor 20
buf[0x12] = 0x00;
buf[0x13] = 0x14;
buf[0x12] = (byte)0x00;
buf[0x13] = (byte)0x14;
}
buf[20] = IsRemovable() ? 0x20 : 0x00;
buf[20] = IsRemovable() ? (byte)0x20 : (byte)0x00;
// Hard-sectored
buf[20] |= 0x40;
buf[20] |= (byte)0x40;
pages[3] = buf;
}
void Disk::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
void Disk::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(24);
vector<byte> buf(24);
// No changeable area
if (changeable) {
@ -572,24 +569,24 @@ void Disk::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
uint64_t cylinders = disk.blocks;
cylinders >>= 3;
cylinders /= 25;
buf[0x02] = (BYTE)(cylinders >> 16);
buf[0x03] = (BYTE)(cylinders >> 8);
buf[0x04] = (BYTE)cylinders;
buf[0x02] = (byte)(cylinders >> 16);
buf[0x03] = (byte)(cylinders >> 8);
buf[0x04] = (byte)cylinders;
// Fix the head at 8
buf[0x05] = 0x8;
buf[0x05] = (byte)0x8;
// Medium rotation rate 7200
buf[0x14] = 0x1c;
buf[0x15] = 0x20;
buf[0x14] = (byte)0x1c;
buf[0x15] = (byte)0x20;
}
pages[4] = buf;
}
void Disk::AddCachePage(map<int, vector<BYTE>>& pages, bool changeable) const
void Disk::AddCachePage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(12);
vector<byte> buf(12);
// No changeable area
if (changeable) {
@ -601,26 +598,26 @@ void Disk::AddCachePage(map<int, vector<BYTE>>& pages, bool changeable) const
// Only read cache is valid
// Disable pre-fetch transfer length
buf[0x04] = 0xff;
buf[0x05] = 0xff;
buf[0x04] = (byte)0xff;
buf[0x05] = (byte)0xff;
// Maximum pre-fetch
buf[0x08] = 0xff;
buf[0x09] = 0xff;
buf[0x08] = (byte)0xff;
buf[0x09] = (byte)0xff;
// Maximum pre-fetch ceiling
buf[0x0a] = 0xff;
buf[0x0b] = 0xff;
buf[0x0a] = (byte)0xff;
buf[0x0b] = (byte)0xff;
pages[8] = buf;
}
void Disk::AddVendorPage(map<int, vector<BYTE>>&, int, bool) const
void Disk::AddVendorPage(map<int, vector<byte>>&, int, bool) const
{
// Nothing to add by default
}
void Disk::Format(const DWORD *cdb)
void Disk::Format(const vector<int>& cdb)
{
CheckReady();
@ -631,7 +628,7 @@ void Disk::Format(const DWORD *cdb)
}
// TODO Read more than one block in a single call. Currently blocked by the the track-oriented cache
int Disk::Read(const DWORD *, BYTE *buf, uint64_t block)
int Disk::Read(const vector<int>&, BYTE *buf, uint64_t block)
{
LOGTRACE("%s", __PRETTY_FUNCTION__)
@ -643,7 +640,7 @@ int Disk::Read(const DWORD *, BYTE *buf, uint64_t block)
}
// leave it to the cache
if (!disk.dcache->ReadSector(buf, block)) {
if (!disk.dcache->ReadSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
}
@ -670,7 +667,7 @@ int Disk::WriteCheck(uint64_t block)
}
// TODO Write more than one block in a single call. Currently blocked by the track-oriented cache
void Disk::Write(const DWORD *, BYTE *buf, uint64_t block)
void Disk::Write(const vector<int>&, const BYTE *buf, uint64_t block)
{
LOGTRACE("%s", __PRETTY_FUNCTION__)
@ -690,7 +687,7 @@ void Disk::Write(const DWORD *, BYTE *buf, uint64_t block)
}
// Leave it to the cache
if (!disk.dcache->WriteSector(buf, block)) {
if (!disk.dcache->WriteSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
}
}
@ -718,7 +715,7 @@ void Disk::Seek10()
}
}
bool Disk::StartStop(const DWORD *cdb)
bool Disk::StartStop(const vector<int>& cdb)
{
bool start = cdb[4] & 0x01;
bool load = cdb[4] & 0x02;
@ -750,7 +747,7 @@ bool Disk::StartStop(const DWORD *cdb)
return true;
}
bool Disk::SendDiag(const DWORD *cdb) const
bool Disk::SendDiag(const vector<int>& cdb) const
{
// Do not support PF bit
if (cdb[1] & 0x10) {
@ -776,7 +773,12 @@ void Disk::ReadCapacity10()
BYTE *buf = ctrl->buffer;
// Create end of logical block address (disk.blocks-1)
uint32_t blocks = disk.blocks - 1;
uint64_t blocks = disk.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;
}
buf[0] = (BYTE)(blocks >> 24);
buf[1] = (BYTE)(blocks >> 16);
buf[2] = (BYTE)(blocks >> 8);

View File

@ -59,16 +59,16 @@ public:
Disk(Disk&) = delete;
Disk& operator=(const Disk&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
void MediumChanged();
bool Eject(bool) override;
// Command helpers
virtual int WriteCheck(uint64_t);
virtual void Write(const DWORD *, BYTE *, uint64_t);
virtual void Write(const vector<int>&, const BYTE *, uint64_t);
virtual int Read(const DWORD *, BYTE *, uint64_t);
virtual int Read(const vector<int>&, BYTE *, uint64_t);
uint32_t GetSectorSizeInBytes() const;
bool IsSectorSizeConfigurable() const;
@ -111,27 +111,27 @@ private:
void ReadWriteLong10();
void ReadWriteLong16();
void ReadCapacity16_ReadLong16();
void Format(const DWORD *);
bool SendDiag(const DWORD *) const;
bool StartStop(const DWORD *);
void Format(const vector<int>&);
bool SendDiag(const vector<int>&) const;
bool StartStop(const vector<int>&);
void ValidateBlockAddress(access_mode) const;
bool CheckAndGetStartAndCount(uint64_t&, uint32_t&, access_mode);
int ModeSense6(const DWORD *, BYTE *, int) override;
int ModeSense10(const DWORD *, BYTE *, int) override;
int ModeSense6(const vector<int>&, BYTE *, int) const override;
int ModeSense10(const vector<int>&, BYTE *, int) const override;
protected:
virtual void Open(const Filepath&);
virtual void SetDeviceParameters(BYTE *) const;
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
virtual void AddErrorPage(map<int, vector<BYTE>>&, bool) const;
virtual void AddFormatPage(map<int, vector<BYTE>>&, bool) const;
virtual void AddDrivePage(map<int, vector<BYTE>>&, bool) const;
void AddCachePage(map<int, vector<BYTE>>&, bool) const;
virtual void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const;
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
virtual void AddErrorPage(map<int, vector<byte>>&, bool) const;
virtual void AddFormatPage(map<int, vector<byte>>&, bool) const;
virtual void AddDrivePage(map<int, vector<byte>>&, bool) const;
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 SetSectorSizeInBytes(uint32_t);

View File

@ -38,11 +38,11 @@ DiskTrack::~DiskTrack()
}
}
void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff)
void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
{
ASSERT(track >= 0);
ASSERT((sectors > 0) && (sectors <= 0x100));
ASSERT(imgoff >= 0);
assert(track >= 0);
assert((sectors > 0) && (sectors <= 0x100));
assert(imgoff >= 0);
// Set Parameters
dt.track = track;
@ -51,10 +51,10 @@ void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff)
dt.raw = raw;
// Not initialized (needs to be loaded)
dt.init = FALSE;
dt.init = false;
// Not Changed
dt.changed = FALSE;
dt.changed = false;
// Offset to actual data
dt.imgoffset = imgoff;
@ -64,15 +64,15 @@ bool DiskTrack::Load(const Filepath& path)
{
// Not needed if already loaded
if (dt.init) {
ASSERT(dt.buffer);
ASSERT(dt.changemap);
assert(dt.buffer);
assert(dt.changemap);
return true;
}
// Calculate offset (previous tracks are considered to hold 256 sectors)
off_t offset = ((off_t)dt.track << 8);
if (dt.raw) {
ASSERT(dt.size == 11);
assert(dt.size == 11);
offset *= 0x930;
offset += 0x10;
} else {
@ -86,12 +86,12 @@ bool DiskTrack::Load(const Filepath& path)
int length = dt.sectors << dt.size;
// Allocate buffer memory
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
if (dt.buffer == nullptr) {
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
}
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
}
dt.length = length;
}
@ -103,14 +103,14 @@ bool DiskTrack::Load(const Filepath& path)
if (dt.length != (DWORD)length) {
free(dt.buffer);
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
}
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
}
dt.length = length;
}
// Reserve change map memory
if (dt.changemap == nullptr) {
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
dt.maplen = dt.sectors;
}
@ -121,16 +121,16 @@ bool DiskTrack::Load(const Filepath& path)
// 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.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
dt.maplen = dt.sectors;
}
// Clear changemap
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
// Read from File
Fileio fio;
if (!fio.OpenDIO(path, Fileio::ReadOnly)) {
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
return false;
}
if (dt.raw) {
@ -165,8 +165,8 @@ bool DiskTrack::Load(const Filepath& path)
fio.Close();
// Set a flag and end normally
dt.init = TRUE;
dt.changed = FALSE;
dt.init = true;
dt.changed = false;
return true;
}
@ -183,12 +183,12 @@ bool DiskTrack::Save(const Filepath& path)
}
// Need to write
ASSERT(dt.buffer);
ASSERT(dt.changemap);
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
assert(dt.buffer);
assert(dt.changemap);
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
// Writing in RAW mode is not allowed
ASSERT(!dt.raw);
assert(!dt.raw);
// Calculate offset (previous tracks are considered to hold 256 sectors)
off_t offset = ((off_t)dt.track << 8);
@ -202,7 +202,7 @@ bool DiskTrack::Save(const Filepath& path)
// Open file
Fileio fio;
if (!fio.Open(path, Fileio::ReadWrite)) {
if (!fio.Open(path, Fileio::OpenMode::ReadWrite)) {
return false;
}
@ -250,15 +250,14 @@ bool DiskTrack::Save(const Filepath& path)
fio.Close();
// Drop the change flag and exit
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
dt.changed = FALSE;
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
dt.changed = false;
return true;
}
bool DiskTrack::ReadSector(BYTE *buf, int sec) const
{
ASSERT(buf);
ASSERT((sec >= 0) && (sec < 0x100));
assert((sec >= 0) && (sec < 0x100));
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
// Error if not initialized
@ -272,8 +271,8 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
}
// Copy
ASSERT(dt.buffer);
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
assert(dt.buffer);
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
// Success
@ -282,9 +281,8 @@ bool DiskTrack::ReadSector(BYTE *buf, int sec) const
bool DiskTrack::WriteSector(const BYTE *buf, int sec)
{
ASSERT(buf);
ASSERT((sec >= 0) && (sec < 0x100));
ASSERT(!dt.raw);
assert((sec >= 0) && (sec < 0x100));
assert(!dt.raw);
// Error if not initialized
if (!dt.init) {
@ -301,8 +299,8 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
int length = 1 << dt.size;
// Compare
ASSERT(dt.buffer);
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
assert(dt.buffer);
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
if (memcmp(buf, &dt.buffer[offset], length) == 0) {
// Exit normally since it's attempting to write the same thing
return true;
@ -310,8 +308,8 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
// Copy, change
memcpy(&dt.buffer[offset], buf, length);
dt.changemap[sec] = TRUE;
dt.changed = TRUE;
dt.changemap[sec] = true;
dt.changed = true;
// Success
return true;
@ -324,23 +322,12 @@ bool DiskTrack::WriteSector(const BYTE *buf, int sec)
//===========================================================================
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
{
ASSERT(blocks > 0);
ASSERT(imgoff >= 0);
assert(blocks > 0);
assert(imgoff >= 0);
// Cache work
for (int i = 0; i < CACHE_MAX; i++) {
cache[i].disktrk = nullptr;
cache[i].serial = 0;
}
// Other
serial = 0;
sec_path = path;
sec_size = size;
sec_blocks = blocks;
cd_raw = FALSE;
imgoffset = imgoff;
}
DiskCache::~DiskCache()
@ -349,22 +336,19 @@ DiskCache::~DiskCache()
Clear();
}
void DiskCache::SetRawMode(BOOL raw)
void DiskCache::SetRawMode(bool raw)
{
// Configuration
cd_raw = raw;
}
bool DiskCache::Save()
bool DiskCache::Save() const
{
// Save track
for (int i = 0; i < CACHE_MAX; i++) {
// Is it a valid track?
if (cache[i].disktrk) {
// Save
if (!cache[i].disktrk->Save(sec_path)) {
return false;
}
for (cache_t c : cache) {
// Save if this is a valid track
if (c.disktrk && !c.disktrk->Save(sec_path)) {
return false;
}
}
@ -378,7 +362,7 @@ bool DiskCache::Save()
//---------------------------------------------------------------------------
bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const
{
ASSERT((index >= 0) && (index < CACHE_MAX));
assert((index >= 0) && (index < CACHE_MAX));
// false if unused
if (!cache[index].disktrk) {
@ -395,17 +379,17 @@ bool DiskCache::GetCache(int index, int& track, DWORD& aserial) const
void DiskCache::Clear()
{
// Free the cache
for (int i = 0; i < CACHE_MAX; i++) {
if (cache[i].disktrk) {
delete cache[i].disktrk;
cache[i].disktrk = nullptr;
for (cache_t& c : cache) {
if (c.disktrk) {
delete c.disktrk;
c.disktrk = nullptr;
}
}
}
bool DiskCache::ReadSector(BYTE *buf, int block)
bool DiskCache::ReadSector(BYTE *buf, uint32_t block)
{
ASSERT(sec_size != 0);
assert(sec_size != 0);
// Update first
UpdateSerialNumber();
@ -423,9 +407,9 @@ bool DiskCache::ReadSector(BYTE *buf, int block)
return disktrk->ReadSector(buf, block & 0xff);
}
bool DiskCache::WriteSector(const BYTE *buf, int block)
bool DiskCache::WriteSector(const BYTE *buf, uint32_t block)
{
ASSERT(sec_size != 0);
assert(sec_size != 0);
// Update first
UpdateSerialNumber();
@ -450,17 +434,15 @@ bool DiskCache::WriteSector(const BYTE *buf, int block)
//---------------------------------------------------------------------------
DiskTrack* DiskCache::Assign(int track)
{
ASSERT(sec_size != 0);
ASSERT(track >= 0);
assert(sec_size != 0);
assert(track >= 0);
// First, check if it is already assigned
for (int i = 0; i < CACHE_MAX; i++) {
if (cache[i].disktrk) {
if (cache[i].disktrk->GetTrack() == track) {
// Track match
cache[i].serial = serial;
return cache[i].disktrk;
}
for (cache_t c : cache) {
if (c.disktrk && c.disktrk->GetTrack() == track) {
// Track match
c.serial = serial;
return c.disktrk;
}
}
@ -487,7 +469,7 @@ DiskTrack* DiskCache::Assign(int track)
// Compare candidate with serial and update to smaller one
for (int i = 0; i < CACHE_MAX; i++) {
ASSERT(cache[i].disktrk);
assert(cache[i].disktrk);
// Compare and update the existing serial
if (cache[i].serial < s) {
@ -522,13 +504,13 @@ DiskTrack* DiskCache::Assign(int track)
//---------------------------------------------------------------------------
bool DiskCache::Load(int index, int track, DiskTrack *disktrk)
{
ASSERT((index >= 0) && (index < CACHE_MAX));
ASSERT(track >= 0);
ASSERT(!cache[index].disktrk);
assert((index >= 0) && (index < CACHE_MAX));
assert(track >= 0);
assert(!cache[index].disktrk);
// Get the number of sectors on this track
int sectors = sec_blocks - (track << 8);
ASSERT(sectors > 0);
assert(sectors > 0);
if (sectors > 0x100) {
sectors = 0x100;
}
@ -562,9 +544,9 @@ void DiskCache::UpdateSerialNumber()
return;
}
// Clear serial of all caches (loop in 32bit)
for (int i = 0; i < CACHE_MAX; i++) {
cache[i].serial = 0;
// Clear serial of all caches
for (cache_t& c : cache) {
c.serial = 0;
}
}

View File

@ -25,18 +25,19 @@ static const int CACHE_MAX = 16;
class DiskTrack
{
private:
struct {
int track; // Track Number
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
int sectors; // Number of sectors(<0x100)
DWORD length; // Data buffer length
BYTE *buffer; // Data buffer
BOOL init; // Is it initilized?
BOOL changed; // Changed flag
DWORD maplen; // Changed map length
BOOL *changemap; // Changed map
BOOL raw; // RAW mode flag
off_t imgoffset; // Offset to actual data
int sectors; // Number of sectors(<0x100)
DWORD length; // Data buffer length
BYTE *buffer; // Data buffer
bool init; // Is it initilized?
bool changed; // Changed flag
DWORD maplen; // Changed map length
bool *changemap; // Changed map
bool raw; // RAW mode flag
off_t imgoffset; // Offset to actual data
} dt = {};
public:
@ -48,7 +49,7 @@ public:
private:
friend class DiskCache;
void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0);
void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0);
bool Load(const Filepath& path);
bool Save(const Filepath& path);
@ -73,12 +74,12 @@ public:
DiskCache(DiskCache&) = delete;
DiskCache& operator=(const DiskCache&) = delete;
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
void SetRawMode(bool); // CD-ROM raw mode setting
// Access
bool Save(); // Save and release all
bool ReadSector(BYTE *buf, int block); // Sector Read
bool WriteSector(const BYTE *buf, int block); // Sector Write
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, DWORD& serial) const; // Get cache information
private:
@ -89,12 +90,12 @@ private:
void UpdateSerialNumber(); // Update serial number
// Internal data
cache_t cache[CACHE_MAX]; // Cache management
DWORD serial; // Last serial number
cache_t cache[CACHE_MAX] = {}; // Cache management
DWORD serial = 0; // Last serial number
Filepath sec_path; // Path
int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
int sec_blocks; // Blocks per sector
BOOL cd_raw; // CD-ROM RAW mode
bool cd_raw = false; // CD-ROM RAW mode
off_t imgoffset; // Offset to actual data
};

View File

@ -30,22 +30,22 @@ public:
using operation = void (T::*)();
using command_t = struct _command_t {
const char* name;
const char *name;
operation execute;
_command_t(const char* _name, operation _execute) : name(_name), execute(_execute) { };
_command_t(const char *_name, operation _execute) : name(_name), execute(_execute) { };
};
unordered_map<scsi_command, unique_ptr<command_t>> commands;
void AddCommand(scsi_command opcode, const char* name, operation execute)
void Add(scsi_command opcode, const char *name, operation execute)
{
commands[opcode] = make_unique<command_t>(name, execute);
}
bool Dispatch(T *instance, DWORD cmd)
bool Dispatch(T *instance, scsi_command cmd)
{
if (const auto& it = commands.find(static_cast<scsi_command>(cmd)); it != commands.end()) {
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, it->second->name, (uint32_t)cmd)
if (const auto& it = commands.find(cmd); it != commands.end()) {
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, it->second->name, (int)cmd)
(instance->*it->second->execute)();

View File

@ -12,20 +12,7 @@
//
// Features of the host services device:
//
// 1. Vendor-specific mode page 0x20 returns the current date and time (realtime clock)
//
// typedef struct {
// // Major and minor version of this data structure
// uint8_t major_version;
// uint8_t minor_version;
// // Current date and time, with daylight savings time adjustment applied
// uint8_t year; // year - 1900
// uint8_t month; // 0-11
// uint8_t day; // 1-31
// uint8_t hour; // 0-23
// uint8_t minute; // 0-59
// uint8_t second; // 0-59
// } mode_page_datetime;
// 1. Vendor-specific mode page 0x20 returns the current date and time, see mode_page_datetime
//
// 2. START/STOP UNIT shuts down RaSCSI or shuts down/reboots the Raspberry Pi
// a) !start && !load (STOP): Shut down RaSCSI
@ -40,16 +27,16 @@
using namespace scsi_defs;
HostServices::HostServices() : ModePageDevice("SCHS")
HostServices::HostServices(const DeviceFactory *factory) : ModePageDevice("SCHS"), device_factory(factory)
{
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &HostServices::TestUnitReady);
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &HostServices::StartStopUnit);
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &HostServices::TestUnitReady);
dispatcher.Add(scsi_command::eCmdStartStop, "StartStopUnit", &HostServices::StartStopUnit);
}
bool HostServices::Dispatch()
bool HostServices::Dispatch(scsi_command cmd)
{
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
void HostServices::TestUnitReady()
@ -58,7 +45,7 @@ void HostServices::TestUnitReady()
EnterStatusPhase();
}
vector<BYTE> HostServices::InquiryInternal() const
vector<byte> HostServices::InquiryInternal() const
{
return HandleInquiry(device_type::PROCESSOR, scsi_level::SPC_3, false);
}
@ -70,7 +57,7 @@ void HostServices::StartStopUnit()
if (!start) {
// Flush any caches
for (Device *device : DeviceFactory::instance().GetAllDevices()) {
for (Device *device : device_factory->GetAllDevices()) {
device->FlushCache();
}
@ -96,14 +83,14 @@ void HostServices::StartStopUnit()
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
int HostServices::ModeSense6(const vector<int>& cdb, 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);
}
auto length = (int)cdb[4];
int length = cdb[4];
if (length > max_length) {
length = max_length;
}
@ -127,7 +114,7 @@ int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf, int max_length)
return size;
}
int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
int HostServices::ModeSense10(const vector<int>& cdb, BYTE *buf, int max_length) const
{
// Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) {
@ -159,33 +146,31 @@ int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
return size;
}
void HostServices::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void HostServices::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
{
if (page == 0x20 || page == 0x3f) {
AddRealtimeClockPage(pages, changeable);
}
}
void HostServices::AddRealtimeClockPage(map<int, vector<BYTE>>& pages, bool changeable) const
void HostServices::AddRealtimeClockPage(map<int, vector<byte>>& pages, bool changeable) const
{
if (!changeable) {
vector<BYTE> buf(10);
// Data structure version 1.0
buf[2] = 0x01;
buf[3] = 0x00;
std::time_t t = std::time(nullptr);
tm localtime;
localtime_r(&t, &localtime);
buf[4] = (BYTE)localtime.tm_year;
buf[5] = (BYTE)localtime.tm_mon;
buf[6] = (BYTE)localtime.tm_mday;
buf[7] = (BYTE)localtime.tm_hour;
buf[8] = (BYTE)localtime.tm_min;
// Ignore leap second for simplicity
buf[9] = (BYTE)(localtime.tm_sec < 60 ? localtime.tm_sec : 59);
mode_page_datetime datetime;
datetime.year = (uint8_t)localtime.tm_year;
datetime.month = (uint8_t)localtime.tm_mon;
datetime.day = (uint8_t)localtime.tm_mday;
datetime.hour = (uint8_t)localtime.tm_hour;
datetime.minute = (uint8_t)localtime.tm_min;
// Ignore leap second for simplicity
datetime.second = (uint8_t)(localtime.tm_sec < 60 ? localtime.tm_sec : 59);
vector<byte> buf(10);
memcpy(&buf[2], &datetime, sizeof(datetime));
pages[32] = buf;
}
}

View File

@ -16,19 +16,21 @@
using namespace std;
class DeviceFactory;
class HostServices: public ModePageDevice
{
public:
HostServices();
explicit HostServices(const DeviceFactory *);
~HostServices() override = default;
HostServices(HostServices&) = delete;
HostServices& operator=(const HostServices&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
vector<BYTE> InquiryInternal() const override;
vector<byte> InquiryInternal() const override;
void TestUnitReady() override;
void StartStopUnit();
@ -36,16 +38,31 @@ public:
protected:
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
private:
using mode_page_datetime = struct __attribute__((packed)) {
// Major and minor version of this data structure (1.0)
uint8_t major_version = 0x01;
uint8_t minor_version = 0x00;
// Current date and time, with daylight savings time adjustment applied
uint8_t year; // year - 1900
uint8_t month; // 0-11
uint8_t day; // 1-31
uint8_t hour; // 0-23
uint8_t minute; // 0-59
uint8_t second; // 0-59
};
using super = ModePageDevice;
Dispatcher<HostServices> dispatcher;
int ModeSense6(const DWORD *, BYTE *, int) override;
int ModeSense10(const DWORD *, BYTE *, int) override;
int ModeSense6(const vector<int>&, BYTE *, int) const override;
int ModeSense10(const vector<int>&, BYTE *, int) const override;
void AddRealtimeClockPage(map<int, vector<BYTE>>&, bool) const;
void AddRealtimeClockPage(map<int, vector<byte>>&, bool) const;
const DeviceFactory *device_factory;
};

View File

@ -18,19 +18,19 @@ using namespace scsi_defs;
ModePageDevice::ModePageDevice(const string& id) : PrimaryDevice(id)
{
dispatcher.AddCommand(eCmdModeSense6, "ModeSense6", &ModePageDevice::ModeSense6);
dispatcher.AddCommand(eCmdModeSense10, "ModeSense10", &ModePageDevice::ModeSense10);
dispatcher.AddCommand(eCmdModeSelect6, "ModeSelect6", &ModePageDevice::ModeSelect6);
dispatcher.AddCommand(eCmdModeSelect10, "ModeSelect10", &ModePageDevice::ModeSelect10);
dispatcher.Add(scsi_command::eCmdModeSense6, "ModeSense6", &ModePageDevice::ModeSense6);
dispatcher.Add(scsi_command::eCmdModeSense10, "ModeSense10", &ModePageDevice::ModeSense10);
dispatcher.Add(scsi_command::eCmdModeSelect6, "ModeSelect6", &ModePageDevice::ModeSelect6);
dispatcher.Add(scsi_command::eCmdModeSelect10, "ModeSelect10", &ModePageDevice::ModeSelect10);
}
bool ModePageDevice::Dispatch()
bool ModePageDevice::Dispatch(scsi_command cmd)
{
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) const
int ModePageDevice::AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const
{
if (max_length < 0) {
return 0;
@ -44,7 +44,7 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page)
// Mode page data mapped to the respective page numbers, C++ maps are ordered by key
map<int, vector<BYTE>> pages;
map<int, vector<byte>> pages;
AddModePages(pages, page, changeable);
if (pages.empty()) {
@ -53,9 +53,9 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
}
// Holds all mode page data
vector<BYTE> result;
vector<byte> result;
vector<BYTE> page0;
vector<byte> page0;
for (auto const& [index, data] : pages) {
// The specification mandates that page 0 must be returned after all others
if (index) {
@ -64,9 +64,9 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
// Page data
result.insert(result.end(), data.begin(), data.end());
// Page code, PS bit may already have been set
result[offset] |= index;
result[offset] |= (byte)index;
// Page payload size
result[offset + 1] = (BYTE)(data.size() - 2);
result[offset + 1] = (byte)(data.size() - 2);
}
else {
page0 = data;
@ -80,7 +80,7 @@ int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length) co
// Page data
result.insert(result.end(), page0.begin(), page0.end());
// Page payload size
result[offset + 1] = (BYTE)(page0.size() - 2);
result[offset + 1] = (byte)(page0.size() - 2);
}
// Do not return more than the requested number of bytes
@ -104,7 +104,7 @@ void ModePageDevice::ModeSense10()
EnterDataInPhase();
}
void ModePageDevice::ModeSelect(const DWORD*, const BYTE *, int)
void ModePageDevice::ModeSelect(const vector<int>&, const BYTE *, int)
{
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
}

View File

@ -25,16 +25,14 @@ public:
ModePageDevice(ModePageDevice&) = delete;
ModePageDevice& operator=(const ModePageDevice&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
vector<BYTE> InquiryInternal() const override = 0;
virtual void ModeSelect(const DWORD *, const BYTE *, int);
virtual void ModeSelect(const vector<int>&, const BYTE *, int);
protected:
int AddModePages(const DWORD *, BYTE *, int) const;
virtual void AddModePages(map<int, vector<BYTE>>&, int, bool) const = 0;
int AddModePages(const vector<int>&, BYTE *, int) const;
virtual void AddModePages(map<int, vector<byte>>&, int, bool) const = 0;
private:
@ -42,8 +40,8 @@ private:
Dispatcher<ModePageDevice> dispatcher;
virtual int ModeSense6(const DWORD *, BYTE *, int) = 0;
virtual int ModeSense10(const DWORD *, BYTE *, int) = 0;
virtual int ModeSense6(const vector<int>&, BYTE *, int) const = 0;
virtual int ModeSense10(const vector<int>&, BYTE *, int) const = 0;
void ModeSense6();
void ModeSense10();

View File

@ -18,17 +18,17 @@ using namespace scsi_defs;
PrimaryDevice::PrimaryDevice(const string& id) : ScsiPrimaryCommands(), Device(id)
{
// Mandatory SCSI primary commands
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
dispatcher.AddCommand(eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
dispatcher.AddCommand(eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
dispatcher.Add(scsi_command::eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
dispatcher.Add(scsi_command::eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
// Optional commands used by all RaSCSI devices
dispatcher.AddCommand(eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
dispatcher.Add(scsi_command::eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
}
bool PrimaryDevice::Dispatch()
bool PrimaryDevice::Dispatch(scsi_command cmd)
{
return dispatcher.Dispatch(this, ctrl->cmd[0]);
return dispatcher.Dispatch(this, cmd);
}
void PrimaryDevice::SetController(AbstractController *c)
@ -51,7 +51,7 @@ void PrimaryDevice::Inquiry()
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
vector<BYTE> buf = InquiryInternal();
vector<byte> buf = InquiryInternal();
size_t allocation_length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
if (allocation_length > buf.size()) {
@ -121,7 +121,7 @@ void PrimaryDevice::RequestSense()
ctrl->status = 0x00;
}
vector<BYTE> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
size_t allocation_length = ctrl->cmd[4];
if (allocation_length > buf.size()) {
@ -160,9 +160,9 @@ void PrimaryDevice::CheckReady()
LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__)
}
vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const
vector<byte> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const
{
vector<BYTE> buf(0x1F + 5);
vector<byte> buf(0x1F + 5);
// Basic data
// buf[0] ... SCSI device type
@ -170,11 +170,11 @@ vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
// buf[2] ... SCSI compliance level of command system
// buf[3] ... SCSI compliance level of Inquiry response
// buf[4] ... Inquiry additional data
buf[0] = (BYTE)type;
buf[1] = is_removable ? 0x80 : 0x00;
buf[2] = (BYTE)level;
buf[3] = (BYTE)(level >= scsi_level::SCSI_2 ? scsi_level::SCSI_2 : scsi_level::SCSI_1_CCS);
buf[4] = 0x1F;
buf[0] = (byte)type;
buf[1] = (byte)(is_removable ? 0x80 : 0x00);
buf[2] = (byte)level;
buf[3] = (byte)(level >= scsi_level::SCSI_2 ? scsi_level::SCSI_2 : scsi_level::SCSI_1_CCS);
buf[4] = (byte)0x1F;
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
@ -182,7 +182,7 @@ vector<BYTE> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
return buf;
}
vector<BYTE> PrimaryDevice::HandleRequestSense() const
vector<byte> PrimaryDevice::HandleRequestSense() const
{
// Return not ready only if there are no errors
if (!GetStatusCode() && !IsReady()) {
@ -191,15 +191,15 @@ vector<BYTE> PrimaryDevice::HandleRequestSense() const
// Set 18 bytes including extended sense data
vector<BYTE> buf(18);
vector<byte> buf(18);
// Current error
buf[0] = 0x70;
buf[0] = (byte)0x70;
buf[2] = (BYTE)(GetStatusCode() >> 16);
buf[7] = 10;
buf[12] = (BYTE)(GetStatusCode() >> 8);
buf[13] = (BYTE)GetStatusCode();
buf[2] = (byte)(GetStatusCode() >> 16);
buf[7] = (byte)10;
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])

View File

@ -29,7 +29,7 @@ public:
PrimaryDevice(PrimaryDevice&) = delete;
PrimaryDevice& operator=(const PrimaryDevice&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
void SetController(AbstractController *);
virtual bool WriteByteSequence(BYTE *, uint32_t);
@ -37,8 +37,8 @@ public:
protected:
vector<BYTE> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const;
virtual vector<BYTE> InquiryInternal() const = 0;
vector<byte> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const;
virtual vector<byte> InquiryInternal() const = 0;
void CheckReady();
void EnterStatusPhase() { controller->Status(); }
@ -55,7 +55,7 @@ private:
void ReportLuns() override;
void Inquiry() override;
vector<BYTE> HandleRequestSense() const;
vector<byte> HandleRequestSense() const;
Dispatcher<PrimaryDevice> dispatcher;
};

View File

@ -13,10 +13,12 @@
using namespace scsi_defs;
void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length, int sector_size)
void scsi_command_util::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length, int sector_size)
{
assert(length >= 0);
int offset = 0;
// PF
if (cdb[1] & 0x10) {
bool has_valid_page_code = false;
@ -31,7 +33,7 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
buf += 12;
offset += 12;
length -= 12;
}
@ -39,11 +41,11 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
// TODO The length handling is wrong in case of length < size
while (length > 0) {
// Format device page
if (int page = buf[0]; page == 0x03) {
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[0xc] != (BYTE)(sector_size >> 8) || buf[0xd] != (BYTE)sector_size) {
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")
@ -57,9 +59,9 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
}
// Advance to the next page
int size = buf[1] + 2;
int size = buf[offset + 1] + 2;
length -= size;
buf += size;
offset += size;
}
if (!has_valid_page_code) {
@ -72,28 +74,28 @@ void scsi_command_util::ModeSelect(const DWORD *cdb, const BYTE *buf, int length
}
}
void scsi_command_util::EnrichFormatPage(map<int, vector<BYTE>>& pages, bool changeable, int sector_size)
void scsi_command_util::EnrichFormatPage(map<int, vector<byte>>& pages, bool changeable, int sector_size)
{
if (changeable) {
// The sector size is simulated to be changeable, see the MODE SELECT implementation for details
vector<BYTE>& format_page = pages[3];
format_page[12] = (BYTE)(sector_size >> 8);
format_page[13] = (BYTE)sector_size;
vector<byte>& format_page = pages[3];
format_page[12] = (byte)(sector_size >> 8);
format_page[13] = (byte)sector_size;
}
}
void scsi_command_util::AddAppleVendorModePage(map<int, vector<BYTE>>& pages, int, bool changeable)
void scsi_command_util::AddAppleVendorModePage(map<int, vector<byte>>& pages, bool changeable)
{
// Page code 48 (30h) - Apple Vendor Mode Page
// Needed for SCCD for stock Apple driver support
// Needed for SCHD for stock Apple HD SC Setup
vector<BYTE> buf(30);
vector<byte> buf(30);
// No changeable area
if (!changeable) {
BYTE apple_data[] = "APPLE COMPUTER, INC ";
memcpy(&buf[2], apple_data, sizeof(apple_data));
const char APPLE_DATA[] = "APPLE COMPUTER, INC ";
memcpy(&buf[2], APPLE_DATA, sizeof(APPLE_DATA));
}
pages[0x30] = buf;
pages[48] = buf;
}

View File

@ -19,7 +19,7 @@ using namespace std;
namespace scsi_command_util
{
void ModeSelect(const DWORD *, const BYTE *, int, int);
void EnrichFormatPage(map<int, vector<BYTE>>&, bool, int);
void AddAppleVendorModePage(map<int, vector<BYTE>>&, int, bool);
void ModeSelect(const vector<int>&, const BYTE *, int, int);
void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
}

View File

@ -32,55 +32,50 @@
using namespace scsi_defs;
const BYTE SCSIDaynaPort::m_bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff };
// const array<byte, 6> SCSIDaynaPort::m_bcast_addr = { byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff}, byte{0xff} };
// const array<byte, 6> SCSIDaynaPort::m_apple_talk_addr = { byte{0x09}, byte{0x00}, byte{0x07}, byte{0xff}, byte{0xff}, byte{0xff} };
// TODO Disk should not be the superclass
// TODO Disk must not be the superclass
SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
{
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
dispatcher.AddCommand(eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
dispatcher.AddCommand(eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
dispatcher.AddCommand(eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
dispatcher.AddCommand(eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
dispatcher.AddCommand(eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
dispatcher.AddCommand(eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
dispatcher.Add(scsi_command::eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
dispatcher.Add(scsi_command::eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
dispatcher.Add(scsi_command::eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
dispatcher.Add(scsi_command::eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
dispatcher.Add(scsi_command::eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
dispatcher.Add(scsi_command::eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
}
SCSIDaynaPort::~SCSIDaynaPort()
{
// TAP driver release
if (m_tap) {
m_tap->Cleanup();
delete m_tap;
}
m_tap.Cleanup();
}
bool SCSIDaynaPort::Dispatch()
bool SCSIDaynaPort::Dispatch(scsi_command cmd)
{
// TODO As long as DaynaPort suffers from being a subclass of Disk at least reject MODE SENSE and MODE SELECT
if (ctrl->cmd[0] == eCmdModeSense6 || ctrl->cmd[0] == eCmdModeSelect6 ||
ctrl->cmd[0] == eCmdModeSense10 || ctrl->cmd[0] == eCmdModeSelect10) {
if (cmd == scsi_command::eCmdModeSense6 || cmd == scsi_command::eCmdModeSelect6 ||
cmd == scsi_command::eCmdModeSense10 || cmd == scsi_command::eCmdModeSelect10) {
return false;
}
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
{
SetParams(params);
#ifdef __linux__
m_tap = new CTapDriver();
m_bTapEnable = m_tap->Init(GetParams());
m_bTapEnable = m_tap.Init(GetParams());
if(!m_bTapEnable){
LOGERROR("Unable to open the TAP interface")
// Not terminating on regular Linux PCs is helpful for testing
#if !defined(__x86_64__) && !defined(__X86__)
return false;
return false;
#endif
} else {
LOGDEBUG("Tap interface created")
@ -90,39 +85,36 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
SetReady(true);
SetReset(false);
// Generate MAC Address
memset(m_mac_addr, 0x00, 6);
// 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]=0x00;
m_mac_addr[1]=0x80;
m_mac_addr[2]=0x19;
m_mac_addr[3]=0x10;
m_mac_addr[4]=0x98;
m_mac_addr[5]=0xE3;
#endif // linux
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;
}
void SCSIDaynaPort::Open(const Filepath& path)
{
m_tap->OpenDump(path);
m_tap.OpenDump(path);
}
vector<BYTE> SCSIDaynaPort::InquiryInternal() const
vector<byte> SCSIDaynaPort::InquiryInternal() const
{
vector<BYTE> buf = HandleInquiry(device_type::PROCESSOR, scsi_level::SCSI_2, false);
vector<byte> buf = HandleInquiry(device_type::PROCESSOR, scsi_level::SCSI_2, false);
// The Daynaport driver for the Mac expects 37 bytes: Increase additional length and
// add a vendor-specific byte in order to satisfy this driver.
buf[4]++;
buf.push_back(0);
buf[4] = (byte)((int)buf[4] + 1);
buf.push_back((byte)0);
return buf;
}
@ -158,7 +150,7 @@ vector<BYTE> SCSIDaynaPort::InquiryInternal() const
// - The SCSI/Link apparently has about 6KB buffer space for packets.
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
int SCSIDaynaPort::Read(const vector<int>& cdb, BYTE *buf, uint64_t)
{
int rx_packet_size = 0;
auto response = (scsi_resp_read_t*)buf;
@ -183,14 +175,14 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
// The first 2 bytes are reserved for the length of the packet
// The next 4 bytes are reserved for a flag field
//rx_packet_size = m_tap->Rx(response->data);
rx_packet_size = m_tap->Rx(&buf[DAYNAPORT_READ_HEADER_SZ]);
//rx_packet_size = m_tap.Rx(response->data);
rx_packet_size = m_tap.Rx(&buf[DAYNAPORT_READ_HEADER_SZ]);
// If we didn't receive anything, return size of 0
if (rx_packet_size <= 0) {
LOGTRACE("%s No packet received", __PRETTY_FUNCTION__)
response->length = 0;
response->flags = e_no_more_data;
response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ;
}
@ -235,10 +227,10 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
// If there are pending packets to be processed, we'll tell the host that the read
// length was 0.
if (!m_tap->PendingPackets())
if (!m_tap.PendingPackets())
{
response->length = 0;
response->flags = e_no_more_data;
response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ;
}
}
@ -246,7 +238,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
// TODO: Need to do some sort of size checking. The buffer can easily overflow, probably.
// response->length = rx_packet_size;
// if(m_tap->PendingPackets()){
// if(m_tap.PendingPackets()){
// response->flags = e_more_data_available;
// } else {
// response->flags = e_no_more_data;
@ -266,7 +258,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
if(m_tap->PendingPackets()){
if(m_tap.PendingPackets()){
buf[5] = 0x10;
} else {
buf[5] = 0;
@ -281,7 +273,7 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, uint64_t)
} // end while
response->length = 0;
response->flags = e_no_more_data;
response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ;
}
@ -314,25 +306,25 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
// XX XX ... is the actual packet
//
//---------------------------------------------------------------------------
bool SCSIDaynaPort::WriteBytes(const DWORD *cdb, const BYTE *buf, uint64_t)
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const BYTE *buf, uint64_t)
{
auto data_format = (BYTE)cdb[5];
WORD data_length = (WORD)cdb[4] + ((WORD)cdb[3] << 8);
int data_format = cdb[5];
int data_length = cdb[4] + (cdb[3] << 8);
if (data_format == 0x00){
m_tap->Tx(buf, data_length);
m_tap.Tx(buf, 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=(WORD)buf[1] + ((WORD)buf[0] << 8);
m_tap->Tx(&buf[4], data_length);
data_length=buf[1] + (buf[0] << 8);
m_tap.Tx(&buf[4], data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
}
else
{
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format)
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format)
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
}
return true;
@ -354,7 +346,7 @@ bool SCSIDaynaPort::WriteBytes(const DWORD *cdb, const BYTE *buf, uint64_t)
// - long #3: frames lost
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer) const
int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, BYTE *buffer) const
{
int allocation_length = cdb[4] + (cdb[3] << 8);
@ -395,21 +387,21 @@ int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer) const
// seconds
//
//---------------------------------------------------------------------------
bool SCSIDaynaPort::EnableInterface(const DWORD *cdb)
bool SCSIDaynaPort::EnableInterface(const vector<int>& cdb)
{
bool result;
if (cdb[5] & 0x80) {
result = m_tap->Enable();
result = m_tap.Enable();
if (result) {
LOGINFO("The DaynaPort interface has been ENABLED.")
}
else{
LOGWARN("Unable to enable the DaynaPort Interface")
}
m_tap->Flush();
m_tap.Flush();
}
else {
result = m_tap->Disable();
result = m_tap.Disable();
if (result) {
LOGINFO("The DaynaPort interface has been DISABLED.")
}
@ -444,10 +436,10 @@ void SCSIDaynaPort::Read6()
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl->blocks)
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length)
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, ctrl->length)
// Set next block
ctrl->next = record + 1;
@ -464,18 +456,18 @@ void SCSIDaynaPort::Write6()
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
}
DWORD data_format = ctrl->cmd[5];
int data_format = ctrl->cmd[5];
if(data_format == 0x00) {
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8);
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
}
else if (data_format == 0x80) {
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8) + 8;
ctrl->length = ctrl->cmd[4] + (ctrl->cmd[3] << 8) + 8;
}
else {
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format)
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
}
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->length, (int)ctrl->length, (unsigned int)data_format)
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, ctrl->length, ctrl->length, data_format)
if (ctrl->length <= 0) {
throw scsi_error_exception();
@ -531,18 +523,24 @@ void SCSIDaynaPort::SetInterfaceMode()
ctrl->length = RetrieveStats(ctrl->cmd, ctrl->buffer);
switch(ctrl->cmd[5]){
case SCSIDaynaPort::CMD_SCSILINK_SETMODE:
case CMD_SCSILINK_SETMODE:
// TODO Not implemented, do nothing
EnterStatusPhase();
break;
case SCSIDaynaPort::CMD_SCSILINK_SETMAC:
case CMD_SCSILINK_SETMAC:
ctrl->length = 6;
EnterDataOutPhase();
break;
case CMD_SCSILINK_STATS:
case CMD_SCSILINK_ENABLE:
case CMD_SCSILINK_SET:
LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
break;
default:
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[5])
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
break;
}
}
@ -551,7 +549,7 @@ void SCSIDaynaPort::SetMcastAddr()
{
ctrl->length = ctrl->cmd[4];
if (ctrl->length == 0) {
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl->cmd[2])
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2])
throw scsi_error_exception();
}

View File

@ -32,6 +32,9 @@
#include "disk.h"
#include "ctapdriver.h"
#include <string>
#include <array>
using namespace std;
//===========================================================================
//
@ -51,15 +54,15 @@ public:
void Open(const Filepath& path) override;
// Commands
vector<BYTE> InquiryInternal() const override;
int Read(const DWORD *cdb, BYTE *, uint64_t) override;
bool WriteBytes(const DWORD *, const BYTE *, uint64_t);
vector<byte> InquiryInternal() const override;
int Read(const vector<int>&, BYTE *, uint64_t) override;
bool WriteBytes(const vector<int>&, const BYTE *, uint64_t);
int WriteCheck(uint64_t block) override;
int RetrieveStats(const DWORD *cdb, BYTE *buffer) const;
bool EnableInterface(const DWORD *cdb);
int RetrieveStats(const vector<int>&, BYTE *) const;
bool EnableInterface(const vector<int>&);
void SetMacAddr(const DWORD *cdb, BYTE *buffer); // Set MAC address
void SetMacAddr(const vector<int>&, BYTE *); // Set MAC address
void TestUnitReady() override;
void Read6() override;
@ -70,15 +73,15 @@ public:
void EnableInterface();
int GetSendDelay() const override;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
static const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
static const BYTE CMD_SCSILINK_STATS = 0x09;
static const BYTE CMD_SCSILINK_ENABLE = 0x0E;
static const BYTE CMD_SCSILINK_SET = 0x0C;
static const BYTE CMD_SCSILINK_SETMODE = 0x80;
static const BYTE CMD_SCSILINK_SETMAC = 0x40;
static const int CMD_SCSILINK_STATS = 0x09;
static const int CMD_SCSILINK_ENABLE = 0x0E;
static const int CMD_SCSILINK_SET = 0x0C;
static const int CMD_SCSILINK_SETMAC = 0x40;
static const int CMD_SCSILINK_SETMODE = 0x80;
// When we're reading the Linux tap device, most of the messages will not be for us, so we
// need to filter through those. However, we don't want to keep re-reading the packets
@ -96,15 +99,7 @@ private:
Dispatcher<SCSIDaynaPort> dispatcher;
using scsi_cmd_daynaport_write_t = struct __attribute__((packed)) {
BYTE operation_code;
BYTE misc_cdb_information;
BYTE logical_block_address;
uint16_t length;
BYTE format;
};
enum read_data_flags_t : uint32_t {
enum class read_data_flags_t : uint32_t {
e_no_more_data = 0x00000000,
e_more_data_available = 0x00000001,
e_dropped_packets = 0xFFFFFFFF,
@ -113,32 +108,29 @@ private:
using scsi_resp_read_t = struct __attribute__((packed)) {
uint32_t length;
read_data_flags_t flags;
BYTE pad;
BYTE data[ETH_FRAME_LEN + sizeof(uint32_t)]; // Frame length + 4 byte CRC
byte pad;
byte data[ETH_FRAME_LEN + sizeof(uint32_t)]; // Frame length + 4 byte CRC
};
using scsi_resp_link_stats_t = struct __attribute__((packed)) {
BYTE mac_address[6];
byte mac_address[6];
uint32_t frame_alignment_errors;
uint32_t crc_errors;
uint32_t frames_lost;
};
scsi_resp_link_stats_t m_scsi_link_stats = {
.mac_address = { 0x00, 0x80, 0x19, 0x10, 0x98, 0xE3 },//MAC address of @PotatoFi's DayanPort
//MAC address of @PotatoFi's DayanPort
.mac_address = { byte{0x00}, byte{0x80}, byte{0x19}, byte{0x10}, byte{0x98}, byte{0xE3} },
.frame_alignment_errors = 0,
.crc_errors = 0,
.frames_lost = 0,
};
const BYTE m_daynacom_mac_prefix[3] = { 0x00, 0x80, 0x19 };
CTapDriver m_tap;
CTapDriver *m_tap = nullptr;
// TAP driver
// TAP valid flag
bool m_bTapEnable = false;
// TAP valid flag
BYTE m_mac_addr[6];
// MAC Address
static const BYTE m_bcast_addr[6];
static const BYTE m_apple_talk_addr[6];
array<byte, 6> m_mac_addr;
};

View File

@ -29,18 +29,15 @@ SCSIBR::SCSIBR() : Disk("SCBR"), fs(new CFileSys())
// Create host file system
fs->Reset();
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
dispatcher.AddCommand(eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
dispatcher.AddCommand(eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
dispatcher.Add(scsi_command::eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
dispatcher.Add(scsi_command::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
}
SCSIBR::~SCSIBR()
{
// TAP driver release
if (tap) {
tap->Cleanup();
delete tap;
}
tap.Cleanup();
// Release host file system
fs->Reset();
@ -53,8 +50,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
#ifdef __linux__
// TAP Driver Generation
tap = new CTapDriver();
m_bTapEnable = tap->Init(GetParams());
m_bTapEnable = tap.Init(GetParams());
if (!m_bTapEnable){
LOGERROR("Unable to open the TAP interface")
return false;
@ -63,7 +59,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
// Generate MAC Address
memset(mac_addr, 0x00, 6);
if (m_bTapEnable) {
tap->GetMacAddr(mac_addr);
tap.GetMacAddr(mac_addr);
mac_addr[5]++;
}
@ -73,7 +69,7 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
SetReady(m_bTapEnable);
// Not terminating on regular Linux PCs is helpful for testing
// Not terminating on regular Linux PCs is helpful for testing
#if defined(__x86_64__) || defined(__X86__)
return true;
#else
@ -81,32 +77,32 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
#endif
}
bool SCSIBR::Dispatch()
bool SCSIBR::Dispatch(scsi_command cmd)
{
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
vector<BYTE> SCSIBR::InquiryInternal() const
vector<byte> SCSIBR::InquiryInternal() const
{
vector<BYTE> b = HandleInquiry(device_type::COMMUNICATIONS, scsi_level::SCSI_2, false);
vector<byte> b = 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);
auto buf = vector<byte>(0x1F + 8 + 5);
memcpy(buf.data(), b.data(), b.size());
buf[4] = 0x1F + 8;
buf[4] = byte{0x1F + 8};
// Optional function valid flag
buf[36] = '0';
buf[36] = byte{'0'};
// TAP Enable
if (m_bTapEnable) {
buf[37] = '1';
buf[37] = byte{'1'};
}
// CFileSys Enable
buf[38] = '1';
buf[38] = byte{'1'};
return buf;
}
@ -117,7 +113,7 @@ void SCSIBR::TestUnitReady()
EnterStatusPhase();
}
int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
int SCSIBR::GetMessage10(const vector<int>& cdb, BYTE *buf)
{
// Type
int type = cdb[2];
@ -209,7 +205,7 @@ int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
return 0;
}
bool SCSIBR::WriteBytes(const DWORD *cdb, BYTE *buf, uint64_t)
bool SCSIBR::WriteBytes(const vector<int>& cdb, BYTE *buf, uint64_t)
{
// Type
int type = cdb[2];
@ -341,15 +337,13 @@ void SCSIBR::ReceivePacket()
{
static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
assert(tap);
// previous packet has not been received
if (packet_enable) {
return;
}
// Receive packet
packet_len = tap->Rx(packet_buf);
packet_len = tap.Rx(packet_buf);
// Check if received packet
if (memcmp(packet_buf, mac_addr, 6) != 0 && memcmp(packet_buf, bcast_addr, 6) != 0) {
@ -371,8 +365,6 @@ void SCSIBR::ReceivePacket()
void SCSIBR::GetPacketBuf(BYTE *buf)
{
assert(tap);
// Size limit
int len = packet_len;
if (len > 2048) {
@ -388,9 +380,7 @@ void SCSIBR::GetPacketBuf(BYTE *buf)
void SCSIBR::SendPacket(const BYTE *buf, int len)
{
assert(tap);
tap->Tx(buf, len);
tap.Tx(buf, len);
}
//---------------------------------------------------------------------------
@ -611,7 +601,7 @@ void SCSIBR::FS_Create(BYTE *buf)
DWORD nAttribute = ntohl(*dp);
i += sizeof(DWORD);
auto bp = (BOOL*)&buf[i];
auto bp = (int*)&buf[i];
DWORD bForce = ntohl(*bp);
pFcb->fileptr = ntohl(pFcb->fileptr);

View File

@ -19,6 +19,7 @@
#include "os.h"
#include "disk.h"
#include "ctapdriver.h"
#include <string>
//===========================================================================
@ -26,7 +27,6 @@
// SCSI Host Bridge
//
//===========================================================================
class CTapDriver;
class CFileSys;
class SCSIBR : public Disk
@ -40,12 +40,12 @@ public:
SCSIBR& operator=(const SCSIBR&) = delete;
bool Init(const unordered_map<string, string>&) override;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
// Commands
vector<BYTE> InquiryInternal() const override;
int GetMessage10(const DWORD *, BYTE *);
bool WriteBytes(const DWORD *, BYTE *, uint64_t);
vector<byte> InquiryInternal() const override;
int GetMessage10(const vector<int>&, BYTE *);
bool WriteBytes(const vector<int>&, BYTE *, uint64_t);
void TestUnitReady() override;
void GetMessage10();
void SendMessage10();
@ -62,7 +62,7 @@ private:
void GetPacketBuf(BYTE *buf); // Get a packet
void SendPacket(const BYTE *buf, int len); // Send a packet
CTapDriver *tap = nullptr; // TAP driver
CTapDriver tap; // TAP driver
bool m_bTapEnable = false; // TAP valid flag
BYTE mac_addr[6]; // MAC Addres
int packet_len = 0; // Receive packet size

View File

@ -50,13 +50,13 @@ using namespace ras_util;
SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP"), ScsiPrinterCommands()
{
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady);
dispatcher.AddCommand(eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
dispatcher.AddCommand(eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
dispatcher.AddCommand(eCmdWrite6, "Print", &SCSIPrinter::Print);
dispatcher.AddCommand(eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer);
dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic);
dispatcher.AddCommand(eCmdStartStop, "StopPrint", &SCSIPrinter::StopPrint);
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady);
dispatcher.Add(scsi_command::eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
dispatcher.Add(scsi_command::eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
dispatcher.Add(scsi_command::eCmdWrite6, "Print", &SCSIPrinter::Print);
dispatcher.Add(scsi_command::eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer);
dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic);
dispatcher.Add(scsi_command::eCmdStartStop, "StopPrint", &SCSIPrinter::StopPrint);
}
SCSIPrinter::~SCSIPrinter()
@ -81,10 +81,10 @@ bool SCSIPrinter::Init(const unordered_map<string, string>& params)
return true;
}
bool SCSIPrinter::Dispatch()
bool SCSIPrinter::Dispatch(scsi_command cmd)
{
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
void SCSIPrinter::TestUnitReady()
@ -94,7 +94,7 @@ void SCSIPrinter::TestUnitReady()
EnterStatusPhase();
}
vector<BYTE> SCSIPrinter::InquiryInternal() const
vector<byte> SCSIPrinter::InquiryInternal() const
{
return HandleInquiry(device_type::PRINTER, scsi_level::SCSI_2, false);
}
@ -148,7 +148,7 @@ void SCSIPrinter::Print()
length <<= 8;
length |= ctrl->cmd[4];
LOGTRACE("Receiving %d bytes to be printed", length)
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
@ -222,14 +222,14 @@ bool SCSIPrinter::WriteByteSequence(BYTE *buf, uint32_t length)
strcpy(filename, TMP_FILE_PATTERN);
fd = mkstemp(filename);
if (fd == -1) {
LOGERROR("Can't create printer output file: %s", strerror(errno))
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno))
return false;
}
LOGTRACE("Created printer output file '%s'", filename)
}
LOGTRACE("Appending %d byte(s) to printer output file", length)
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename)
auto num_written = (uint32_t)write(fd, buf, length);

View File

@ -31,11 +31,11 @@ public:
SCSIPrinter(SCSIPrinter&) = delete;
SCSIPrinter& operator=(const SCSIPrinter&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
bool Init(const unordered_map<string, string>&) override;
vector<BYTE> InquiryInternal() const override;
vector<byte> InquiryInternal() const override;
void TestUnitReady() override;
void ReserveUnit() override;
void ReleaseUnit() override;
@ -55,7 +55,7 @@ private:
Dispatcher<SCSIPrinter> dispatcher;
char filename[TMP_FILENAME_LENGTH + 1];
char filename[TMP_FILENAME_LENGTH + 1]; //NOSONAR mkstemp() requires a modifiable string
int fd = -1;
int reserving_initiator = NOT_RESERVED;

View File

@ -112,7 +112,7 @@ int CDTrack::GetTrackNo() const
//---------------------------------------------------------------------------
bool CDTrack::IsValid(DWORD lba) const
{
// FALSE if the track itself is invalid
// false if the track itself is invalid
if (!valid) {
return false;
}
@ -131,11 +131,6 @@ bool CDTrack::IsValid(DWORD lba) const
return true;
}
//---------------------------------------------------------------------------
//
// Is audio track
//
//---------------------------------------------------------------------------
bool CDTrack::IsAudio() const
{
assert(valid);
@ -143,18 +138,12 @@ bool CDTrack::IsAudio() const
return audio;
}
//===========================================================================
//
// SCSI CD-ROM
//
//===========================================================================
SCSICD::SCSICD(const unordered_set<uint32_t>& sector_sizes) : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
{
SetSectorSizes(sector_sizes);
dispatcher.AddCommand(eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
dispatcher.AddCommand(eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
dispatcher.Add(scsi_command::eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
dispatcher.Add(scsi_command::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
}
SCSICD::~SCSICD()
@ -162,10 +151,10 @@ SCSICD::~SCSICD()
ClearTrack();
}
bool SCSICD::Dispatch()
bool SCSICD::Dispatch(scsi_command cmd)
{
// The superclass class handles the less specific commands
return dispatcher.Dispatch(this, ctrl->cmd[0]) ? true : super::Dispatch();
return dispatcher.Dispatch(this, cmd) ? true : super::Dispatch(cmd);
}
void SCSICD::Open(const Filepath& path)
@ -179,7 +168,7 @@ void SCSICD::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open CD-ROM file");
}
@ -195,14 +184,14 @@ void SCSICD::Open(const Filepath& path)
OpenPhysical(path);
} else {
// Get file size
if (off_t size = fio.GetFileSize(); size <= 4) {
if (fio.GetFileSize() < 4) {
fio.Close();
throw io_exception("CD-ROM file size must be at least 4 bytes");
}
// Judge whether it is a CUE sheet or an ISO file
TCHAR file[5];
fio.Read(file, 4);
fio.Read((BYTE *)file, 4);
file[4] = '\0';
fio.Close();
@ -223,7 +212,6 @@ void SCSICD::Open(const Filepath& path)
FileSupport::SetPath(path);
// Set RAW flag
assert(disk.dcache);
disk.dcache->SetRawMode(rawfile);
// Attention if ready
@ -241,7 +229,7 @@ void SCSICD::OpenIso(const Filepath& path)
{
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw io_exception("Can't open ISO CD-ROM file");
}
@ -301,7 +289,7 @@ void SCSICD::OpenIso(const Filepath& path)
// Create only one data track
assert(!tracks.size());
auto track = make_unique<CDTrack>();
track->Init(1, 0, GetBlockCount() - 1);
track->Init(1, 0, (int)GetBlockCount() - 1);
track->SetPath(false, path);
tracks.push_back(move(track));
dataindex = 0;
@ -311,7 +299,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
{
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw io_exception("Can't open CD-ROM file");
}
@ -334,7 +322,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
// Create only one data track
ASSERT(!tracks.size());
auto track = make_unique<CDTrack>();
track->Init(1, 0, GetBlockCount() - 1);
track->Init(1, 0, (int)GetBlockCount() - 1);
track->SetPath(false, path);
tracks.push_back(move(track));
dataindex = 0;
@ -347,35 +335,12 @@ void SCSICD::ReadToc()
EnterDataInPhase();
}
vector<BYTE> SCSICD::InquiryInternal() const
vector<byte> SCSICD::InquiryInternal() const
{
return HandleInquiry(device_type::CD_ROM, scsi_level::SCSI_2, true);
//
// The following code worked with the modified Apple CD-ROM drivers. Need to
// test with the original code to see if it works as well....
// buf[4] = 42; // Required
//
// // Fill with blanks
// memset(&buf[8], 0x20, buf[4] - 3);
//
// // Vendor name
// memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
//
// // Product name
// memcpy(&buf[16], "CD-ROM CDU-8003A", 16);
//
// // Revision (XM6 version number)
//// sprintf(rev, "1.9a",
// //// (int)major, (int)(minor >> 4), (int)(minor & 0x0f));
// memcpy(&buf[32], "1.9a", 4);
//
// //strcpy(&buf[35],"A1.9a");
// buf[36]=0x20;
// memcpy(&buf[37],"1999/01/01",10);
}
void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void SCSICD::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
{
super::AddModePages(pages, page, changeable);
@ -390,26 +355,26 @@ void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeab
}
}
void SCSICD::AddCDROMPage(map<int, vector<BYTE>>& pages, bool changeable) const
void SCSICD::AddCDROMPage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(8);
vector<byte> buf(8);
// No changeable area
if (!changeable) {
// 2 seconds for inactive timer
buf[3] = 0x05;
buf[3] = (byte)0x05;
// MSF multiples are 60 and 75 respectively
buf[5] = 60;
buf[7] = 75;
buf[5] = (byte)60;
buf[7] = (byte)75;
}
pages[13] = buf;
}
void SCSICD::AddCDDAPage(map<int, vector<BYTE>>& pages, bool) const
void SCSICD::AddCDDAPage(map<int, vector<byte>>& pages, bool) const
{
vector<BYTE> buf(16);
vector<byte> buf(16);
// Audio waits for operation completion and allows
// PLAY across multiple tracks
@ -417,23 +382,23 @@ void SCSICD::AddCDDAPage(map<int, vector<BYTE>>& pages, bool) const
pages[14] = buf;
}
void SCSICD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void SCSICD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
{
// Page code 48
if (page == 0x30 || page == 0x3f) {
scsi_command_util::AddAppleVendorModePage(pages, page, changeable);
scsi_command_util::AddAppleVendorModePage(pages, changeable);
}
}
int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
int SCSICD::Read(const vector<int>& cdb, BYTE *buf, uint64_t block)
{
assert(buf);
CheckReady();
// Search for the track
int index = SearchTrack(block);
int index = SearchTrack((int)block);
// If invalid, out of range
if (index < 0) {
@ -455,7 +420,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
// Recreate the disk cache
Filepath path;
tracks[index]->GetPath(path);
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), GetBlockCount());
disk.dcache = new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount());
disk.dcache->SetRawMode(rawfile);
// Reset data index
@ -467,9 +432,8 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
return super::Read(cdb, buf, block);
}
int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
int SCSICD::ReadToc(const vector<int>& cdb, BYTE *buf)
{
assert(cdb);
assert(buf);
CheckReady();
@ -489,7 +453,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
// Get and check the last track number
int last = tracks[tracks.size() - 1]->GetTrackNo();
// Except for AA
if ((int)cdb[6] > last && cdb[6] != 0xaa) {
if (cdb[6] > last && cdb[6] != 0xaa) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
@ -498,7 +462,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
if (cdb[6] != 0x00) {
// Advance the track until the track numbers match
while (tracks[index]) {
if ((int)cdb[6] == tracks[index]->GetTrackNo()) {
if (cdb[6] == tracks[index]->GetTrackNo()) {
break;
}
index++;
@ -633,7 +597,7 @@ int SCSICD::SearchTrack(DWORD lba) const
// Listen to the track
assert(tracks[i]);
if (tracks[i]->IsValid(lba)) {
return i;
return (int)i;
}
}

View File

@ -72,19 +72,19 @@ public:
SCSICD(SCSICD&) = delete;
SCSICD& operator=(const SCSICD&) = delete;
bool Dispatch() override;
bool Dispatch(scsi_command) override;
void Open(const Filepath& path) override;
// Commands
vector<BYTE> InquiryInternal() const override;
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override;
int ReadToc(const DWORD *cdb, BYTE *buf);
vector<byte> InquiryInternal() const override;
int Read(const vector<int>&, BYTE *, uint64_t) override;
int ReadToc(const vector<int>&, BYTE *);
protected:
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
private:
@ -92,8 +92,8 @@ private:
Dispatcher<SCSICD> dispatcher;
void AddCDROMPage(map<int, vector<BYTE>>&, bool) const;
void AddCDDAPage(map<int, vector<BYTE>>&, bool) const;
void AddCDROMPage(map<int, vector<byte>>&, bool) const;
void AddCDDAPage(map<int, vector<byte>>&, bool) const;
// Open
void OpenCue(const Filepath& path) const;

View File

@ -20,8 +20,6 @@
#include "scsi_command_util.h"
#include <sstream>
static const char *DEFAULT_PRODUCT = "SCSI HD";
SCSIHD::SCSIHD(const unordered_set<uint32_t>& sector_sizes, bool removable, scsi_defs::scsi_level level)
: Disk(removable ? "SCRM" : "SCHD")
{
@ -79,7 +77,7 @@ void SCSIHD::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open SCSI hard disk file");
}
@ -97,27 +95,27 @@ void SCSIHD::Open(const Filepath& path)
FinalizeSetup(path, size);
}
vector<BYTE> SCSIHD::InquiryInternal() const
vector<byte> SCSIHD::InquiryInternal() const
{
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level, IsRemovable());
}
void SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
void SCSIHD::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length)
{
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
}
void SCSIHD::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
void SCSIHD::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
{
Disk::AddFormatPage(pages, changeable);
scsi_command_util::EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount());
}
void SCSIHD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void SCSIHD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
{
// Page code 48
if (page == 0x30 || page == 0x3f) {
scsi_command_util::AddAppleVendorModePage(pages, page, changeable);
scsi_command_util::AddAppleVendorModePage(pages, changeable);
}
}

View File

@ -21,6 +21,7 @@
class SCSIHD : public Disk, public FileSupport
{
static constexpr const char *DEFAULT_PRODUCT = "SCSI HD";
public:
@ -35,11 +36,11 @@ public:
void Open(const Filepath&) override;
// Commands
vector<BYTE> InquiryInternal() const override;
void ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
vector<byte> InquiryInternal() const override;
void ModeSelect(const vector<int>& cdb, const BYTE *buf, int length) override;
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
private:

View File

@ -25,9 +25,9 @@ const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
// Extract words that are supposed to be little endian
//
//---------------------------------------------------------------------------
static inline WORD getWordLE(const BYTE *b)
static inline int getWordLE(const BYTE *b)
{
return ((WORD)(b[1]) << 8) | b[0];
return (b[1] << 8) | b[0];
}
//---------------------------------------------------------------------------
@ -46,7 +46,7 @@ void SCSIHD_NEC::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open hard disk file");
}
@ -55,11 +55,9 @@ void SCSIHD_NEC::Open(const Filepath& path)
// NEC root sector
BYTE root_sector[512];
if (size >= (off_t)sizeof(root_sector)) {
if (!fio.Read(root_sector, sizeof(root_sector))) {
fio.Close();
throw io_exception("Can't read NEC hard disk file root sector");
}
if (size >= (off_t)sizeof(root_sector) && !fio.Read(root_sector, sizeof(root_sector))) {
fio.Close();
throw io_exception("Can't read NEC hard disk file root sector");
}
fio.Close();
@ -132,31 +130,31 @@ void SCSIHD_NEC::Open(const Filepath& path)
FinalizeSetup(path, size);
}
vector<BYTE> SCSIHD_NEC::InquiryInternal() const
vector<byte> SCSIHD_NEC::InquiryInternal() const
{
return HandleInquiry(device_type::DIRECT_ACCESS, scsi_level::SCSI_1_CCS, false);
}
void SCSIHD_NEC::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
void SCSIHD_NEC::AddErrorPage(map<int, vector<byte>>& pages, bool) const
{
vector<BYTE> buf(8);
vector<byte> buf(8);
// The retry count is 0, and the limit time uses the default value inside the device.
pages[1] = buf;
}
void SCSIHD_NEC::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
void SCSIHD_NEC::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(24);
vector<byte> buf(24);
// Page can be saved
buf[0] = 0x80;
buf[0] = (byte)0x80;
// Make the number of bytes in the physical sector appear mutable (although it cannot actually be)
if (changeable) {
buf[0xc] = 0xff;
buf[0xd] = 0xff;
buf[0xc] = (byte)0xff;
buf[0xd] = (byte)0xff;
pages[3] = buf;
@ -165,40 +163,40 @@ void SCSIHD_NEC::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) c
if (IsReady()) {
// Set the number of tracks in one zone (PC-9801-55 seems to see this value)
buf[0x2] = (BYTE)(heads >> 8);
buf[0x3] = (BYTE)heads;
buf[0x2] = (byte)(heads >> 8);
buf[0x3] = (byte)heads;
// Set the number of sectors per track
buf[0xa] = (BYTE)(sectors >> 8);
buf[0xb] = (BYTE)sectors;
buf[0xa] = (byte)(sectors >> 8);
buf[0xb] = (byte)sectors;
// Set the number of bytes in the physical sector
int size = 1 << disk.size;
buf[0xc] = (BYTE)(size >> 8);
buf[0xd] = (BYTE)size;
buf[0xc] = (byte)(size >> 8);
buf[0xd] = (byte)size;
}
// Set removable attributes (remains of the old days)
if (IsRemovable()) {
buf[20] = 0x20;
buf[20] = (byte)0x20;
}
pages[3] = buf;
}
void SCSIHD_NEC::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
void SCSIHD_NEC::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<BYTE> buf(20);
vector<byte> buf(20);
// No changeable area
if (!changeable && IsReady()) {
// Set the number of cylinders
buf[0x2] = (BYTE)(cylinders >> 16);
buf[0x3] = (BYTE)(cylinders >> 8);
buf[0x4] = (BYTE)cylinders;
buf[0x2] = (byte)(cylinders >> 16);
buf[0x3] = (byte)(cylinders >> 8);
buf[0x4] = (byte)cylinders;
// Set the number of heads
buf[0x5] = (BYTE)heads;
buf[0x5] = (byte)heads;
}
pages[4] = buf;

View File

@ -35,11 +35,11 @@ public:
void Open(const Filepath& path) override;
vector<BYTE> InquiryInternal() const override;
vector<byte> InquiryInternal() const override;
void AddErrorPage(map<int, vector<BYTE>>&, bool) const override;
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
void AddDrivePage(map<int, vector<BYTE>>&, bool) const override;
void AddErrorPage(map<int, vector<byte>>&, bool) const override;
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddDrivePage(map<int, vector<byte>>&, bool) const override;
private:

View File

@ -33,7 +33,7 @@ void SCSIMO::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open MO file");
}
@ -62,7 +62,7 @@ void SCSIMO::Open(const Filepath& path)
}
}
vector<BYTE> SCSIMO::InquiryInternal() const
vector<byte> SCSIMO::InquiryInternal() const
{
return HandleInquiry(device_type::OPTICAL_MEMORY, scsi_level::SCSI_2, true);
}
@ -75,7 +75,7 @@ void SCSIMO::SetDeviceParameters(BYTE *buf) const
buf[2] = 0x03;
}
void SCSIMO::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void SCSIMO::AddModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
{
Disk::AddModePages(pages, page, changeable);
@ -85,22 +85,22 @@ void SCSIMO::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeab
}
}
void SCSIMO::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
void SCSIMO::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
{
Disk::AddFormatPage(pages, changeable);
scsi_command_util::EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount());
}
void SCSIMO::AddOptionPage(map<int, vector<BYTE>>& pages, bool) const
void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
{
vector<BYTE> buf(4);
vector<byte> buf(4);
pages[6] = buf;
// Do not report update blocks
}
void SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
void SCSIMO::ModeSelect(const vector<int>& cdb, const BYTE *buf, int length)
{
scsi_command_util::ModeSelect(cdb, buf, length, 1 << GetSectorSizeShiftCount());
}
@ -110,14 +110,14 @@ void SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Vendor Unique Format Page 20h (MO)
//
//---------------------------------------------------------------------------
void SCSIMO::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
void SCSIMO::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
{
// Page code 20h
if (page != 0x20 && page != 0x3f) {
return;
}
vector<BYTE> buf(12);
vector<byte> buf(12);
// No changeable area
if (changeable) {
@ -198,16 +198,16 @@ void SCSIMO::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changea
}
}
buf[2] = 0; // format mode
buf[3] = 0; // type of format
buf[4] = (BYTE)(blocks >> 24);
buf[5] = (BYTE)(blocks >> 16);
buf[6] = (BYTE)(blocks >> 8);
buf[7] = (BYTE)blocks;
buf[8] = (BYTE)(spare >> 8);
buf[9] = (BYTE)spare;
buf[10] = (BYTE)(bands >> 8);
buf[11] = (BYTE)bands;
buf[2] = (byte)0; // format mode
buf[3] = (byte)0; // type of format
buf[4] = (byte)(blocks >> 24);
buf[5] = (byte)(blocks >> 16);
buf[6] = (byte)(blocks >> 8);
buf[7] = (byte)blocks;
buf[8] = (byte)(spare >> 8);
buf[9] = (byte)spare;
buf[10] = (byte)(bands >> 8);
buf[11] = (byte)bands;
}
pages[32] = buf;

View File

@ -31,19 +31,19 @@ public:
void Open(const Filepath& path) override;
vector<BYTE> InquiryInternal() const override;
void ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
vector<byte> InquiryInternal() const override;
void ModeSelect(const vector<int>&, const BYTE *, int) override;
protected:
void SetDeviceParameters(BYTE *) const override;
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
void AddModePages(map<int, vector<byte>>&, int, bool) const override;
void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
private:
void AddOptionPage(map<int, vector<BYTE>>&, bool) const;
void AddOptionPage(map<int, vector<byte>>&, bool) const;
void SetGeometries(const unordered_map<uint64_t, Geometry>& g) { geometries = g; }
bool SetGeometryForCapacity(uint64_t);

View File

@ -14,12 +14,6 @@
#include "config.h"
//===========================================================================
//
// File I/O
//
//===========================================================================
Fileio::~Fileio()
{
ASSERT(handle == -1);
@ -28,184 +22,107 @@ Fileio::~Fileio()
Close();
}
BOOL Fileio::Load(const Filepath& path, void *buffer, int size)
bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
{
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle < 0);
if (!Open(path, ReadOnly)) {
return FALSE;
}
if (!Read(buffer, size)) {
Close();
return FALSE;
}
Close();
return TRUE;
}
BOOL Fileio::Save(const Filepath& path, const void *buffer, int size)
{
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle < 0);
if (!Open(path, WriteOnly)) {
return FALSE;
}
if (!Write(buffer, size)) {
Close();
return FALSE;
}
Close();
return TRUE;
}
BOOL Fileio::Open(const char *fname, OpenMode mode, BOOL directIO)
{
mode_t omode;
ASSERT(fname);
ASSERT(handle < 0);
assert(fname);
assert(handle < 0);
// Always fail a read from a null array
if (fname[0] == _T('\0')) {
handle = -1;
return FALSE;
return false;
}
// Default mode
omode = directIO ? O_DIRECT : 0;
mode_t omode = directIO ? O_DIRECT : 0;
switch (mode) {
case ReadOnly:
case OpenMode::ReadOnly:
handle = open(fname, O_RDONLY | omode);
break;
case WriteOnly:
case OpenMode::WriteOnly:
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC | omode, 0666);
break;
case ReadWrite:
case OpenMode::ReadWrite:
// Make sure RW does not succeed when reading from CD-ROM
if (access(fname, 0x06) != 0) {
return FALSE;
return false;
}
handle = open(fname, O_RDWR | omode);
break;
default:
ASSERT(FALSE);
assert(false);
break;
}
// Evaluate results
if (handle == -1) {
return FALSE;
}
ASSERT(handle >= 0);
return TRUE;
return handle != -1;
}
BOOL Fileio::Open(const char *fname, OpenMode mode)
bool Fileio::Open(const char *fname, OpenMode mode)
{
return Open(fname, mode, FALSE);
return Open(fname, mode, false);
}
BOOL Fileio::Open(const Filepath& path, OpenMode mode)
bool Fileio::Open(const Filepath& path, OpenMode mode)
{
return Open(path.GetPath(), mode);
}
BOOL Fileio::OpenDIO(const char *fname, OpenMode mode)
bool Fileio::OpenDIO(const char *fname, OpenMode mode)
{
// Open with included O_DIRECT
if (!Open(fname, mode, TRUE)) {
if (!Open(fname, mode, true)) {
// Normal mode retry (tmpfs etc.)
return Open(fname, mode, FALSE);
return Open(fname, mode, false);
}
return TRUE;
return true;
}
BOOL Fileio::OpenDIO(const Filepath& path, OpenMode mode)
bool Fileio::OpenDIO(const Filepath& path, OpenMode mode)
{
return OpenDIO(path.GetPath(), mode);
}
BOOL Fileio::Read(void *buffer, int size) const
bool Fileio::Read(BYTE *buffer, int size) const
{
long count;
assert(buffer);
assert(size > 0);
assert(handle >= 0);
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle >= 0);
count = read(handle, buffer, size);
if (count != size) {
return FALSE;
}
return TRUE;
return read(handle, buffer, size) == size;
}
BOOL Fileio::Write(const void *buffer, int size) const
bool Fileio::Write(const BYTE *buffer, int size) const
{
long count;
assert(buffer);
assert(size > 0);
assert(handle >= 0);
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle >= 0);
count = write(handle, buffer, size);
if (count != size) {
return FALSE;
}
return TRUE;
return write(handle, buffer, size) == size;
}
BOOL Fileio::Seek(off_t offset, BOOL relative) const
bool Fileio::Seek(off_t offset) const
{
ASSERT(handle >= 0);
ASSERT(offset >= 0);
assert(handle >= 0);
assert(offset >= 0);
// Add current position in case of relative seek
if (relative) {
offset += GetFilePos();
}
if (lseek(handle, offset, SEEK_SET) != offset) {
return FALSE;
}
return TRUE;
return lseek(handle, offset, SEEK_SET) == offset;
}
off_t Fileio::GetFileSize() const
{
off_t cur;
off_t end;
ASSERT(handle >= 0);
assert(handle >= 0);
// Get file position in 64bit
cur = GetFilePos();
off_t cur = GetFilePos();
// Get file size in64bitで
end = lseek(handle, 0, SEEK_END);
off_t end = lseek(handle, 0, SEEK_END);
// Return to start position
Seek(cur);
@ -215,19 +132,14 @@ off_t Fileio::GetFileSize() const
off_t Fileio::GetFilePos() const
{
off_t pos;
ASSERT(handle >= 0);
assert(handle >= 0);
// Get file position in 64bit
pos = lseek(handle, 0, SEEK_CUR);
return pos;
return lseek(handle, 0, SEEK_CUR);
}
void Fileio::Close()
{
if (handle != -1) {
close(handle);
handle = -1;

View File

@ -8,35 +8,15 @@
//
//---------------------------------------------------------------------------
#if !defined(fileio_h)
#define fileio_h
#pragma once
#include "filepath.h"
//===========================================================================
//
// Macros (for Load, Save)
//
//===========================================================================
#define PROP_IMPORT(f, p) \
if (!f->Read(&(p), sizeof(p))) {\
return FALSE;\
}\
#define PROP_EXPORT(f, p) \
if (!f->Write(&(p), sizeof(p))) {\
return FALSE;\
}\
//===========================================================================
//
// File I/O
//
//===========================================================================
class Fileio
{
public:
enum OpenMode {
enum class OpenMode {
ReadOnly,
WriteOnly,
ReadWrite
@ -47,25 +27,20 @@ public:
Fileio(Fileio&) = delete;
Fileio& operator=(const Fileio&) = delete;
BOOL Load(const Filepath& path, void *buffer, int size); // Load ROM, RAM
BOOL Save(const Filepath& path, const void *buffer, int size); // Save RAM
BOOL Open(const char *fname, OpenMode mode);
BOOL Open(const Filepath& path, OpenMode mode);
BOOL OpenDIO(const char *fname, OpenMode mode);
BOOL OpenDIO(const Filepath& path, OpenMode mode);
BOOL Seek(off_t offset, BOOL relative = FALSE) const;
BOOL Read(void *buffer, int size) const;
BOOL Write(const void *buffer, int size) const;
bool Open(const char *fname, OpenMode mode);
bool Open(const Filepath& path, OpenMode mode);
bool OpenDIO(const Filepath& path, OpenMode mode);
bool Seek(off_t offset) const;
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();
BOOL IsValid() const { return (BOOL)(handle != -1); }
private:
BOOL Open(const char *fname, OpenMode mode, BOOL directIO);
int handle = -1; // File handle
bool Open(const char *fname, OpenMode mode, bool directIO);
bool OpenDIO(const char *fname, OpenMode mode);
int handle = -1;
};
#endif // fileio_h

View File

@ -77,36 +77,29 @@ DWORD bcm_host_get_peripheral_address(void)
bool GPIOBUS::Init(mode_e mode)
{
#if defined(__x86_64__) || defined(__X86__)
actmode = mode;
// When we're running on x86, there is no hardware to talk to, so just return.
return true;
#else
void *map;
int i;
int j;
int pullmode;
int fd;
#ifdef USE_SEL_EVENT_ENABLE
struct epoll_event ev;
#endif // USE_SEL_EVENT_ENABLE
// Save operation mode
actmode = mode;
#if defined(__x86_64__) || defined(__X86__)
return true;
#else
int i;
#ifdef USE_SEL_EVENT_ENABLE
struct epoll_event ev;
#endif
// Get the base address
baseaddr = (DWORD)bcm_host_get_peripheral_address();
// Open /dev/mem
fd = open("/dev/mem", O_RDWR | O_SYNC);
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
LOGERROR("Error: Unable to open /dev/mem. Are you running as root?")
return false;
}
// Map peripheral region memory
map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr);
if (map == MAP_FAILED) {
LOGERROR("Error: Unable to map memory")
close(fd);
@ -166,16 +159,16 @@ bool GPIOBUS::Init(mode_e mode)
// Set pull up/pull down
#if SIGNAL_CONTROL_MODE == 0
pullmode = GPIO_PULLNONE;
int pullmode = GPIO_PULLNONE;
#elif SIGNAL_CONTROL_MODE == 1
pullmode = GPIO_PULLUP;
int pullmode = GPIO_PULLUP;
#else
pullmode = GPIO_PULLDOWN;
int pullmode = GPIO_PULLDOWN;
#endif
// Initialize all signals
for (i = 0; SignalTable[i] >= 0; i++) {
j = SignalTable[i];
int j = SignalTable[i];
PinSetSignal(j, FALSE);
PinConfig(j, GPIO_INPUT);
PullConfig(j, pullmode);
@ -305,9 +298,6 @@ void GPIOBUS::Cleanup()
#if defined(__x86_64__) || defined(__X86__)
return;
#else
int i;
int pin;
// Release SEL signal interrupt
#ifdef USE_SEL_EVENT_ENABLE
close(selevreq.fd);
@ -325,8 +315,8 @@ void GPIOBUS::Cleanup()
PinConfig(PIN_DTD, GPIO_INPUT);
// Initialize all signals
for (i = 0; SignalTable[i] >= 0; i++) {
pin = SignalTable[i];
for (int i = 0; SignalTable[i] >= 0; i++) {
int pin = SignalTable[i];
PinSetSignal(pin, FALSE);
PinConfig(pin, GPIO_INPUT);
PullConfig(pin, GPIO_PULLNONE);
@ -358,7 +348,7 @@ void GPIOBUS::Reset()
SetSignal(j, OFF);
}
if (actmode == TARGET) {
if (actmode == mode_e::TARGET) {
// Target mode
// Set target signal to input
@ -438,7 +428,7 @@ void GPIOBUS::SetBSY(bool ast)
// Set BSY signal
SetSignal(PIN_BSY, ast);
if (actmode == TARGET) {
if (actmode == mode_e::TARGET) {
if (ast) {
// Turn on ACTIVE signal
SetControl(PIN_ACT, ACT_ON);
@ -474,7 +464,7 @@ bool GPIOBUS::GetSEL() const
void GPIOBUS::SetSEL(bool ast)
{
if (actmode == INITIATOR && ast) {
if (actmode == mode_e::INITIATOR && ast) {
// Turn on ACTIVE signal
SetControl(PIN_ACT, ACT_ON);
}
@ -547,7 +537,7 @@ bool GPIOBUS::GetIO()
{
bool ast = GetSignal(PIN_IO);
if (actmode == INITIATOR) {
if (actmode == mode_e::INITIATOR) {
// Change the data input/output direction by IO signal
if (ast) {
SetControl(PIN_DTD, DTD_IN);
@ -581,7 +571,7 @@ void GPIOBUS::SetIO(bool ast)
{
SetSignal(PIN_IO, ast);
if (actmode == TARGET) {
if (actmode == mode_e::TARGET) {
// Change the data input/output direction by IO signal
if (ast) {
SetControl(PIN_DTD, DTD_OUT);
@ -627,7 +617,7 @@ void GPIOBUS::SetREQ(bool ast)
//---------------------------------------------------------------------------
BYTE GPIOBUS::GetDAT()
{
DWORD data = Acquire();
uint32_t data = Acquire();
data =
((data >> (PIN_DT0 - 0)) & (1 << 0)) |
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
@ -692,7 +682,7 @@ bool GPIOBUS::GetDP() const
int GPIOBUS::CommandHandShake(BYTE *buf)
{
// Only works in TARGET mode
if (actmode != TARGET) {
if (actmode != mode_e::TARGET) {
return 0;
}
@ -818,7 +808,7 @@ int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
// Disable IRQs
DisableIRQ();
if (actmode == TARGET) {
if (actmode == mode_e::TARGET) {
for (i = 0; i < count; i++) {
// Assert the REQ signal
SetSignal(PIN_REQ, ON);
@ -918,7 +908,7 @@ int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
// Disable IRQs
DisableIRQ();
if (actmode == TARGET) {
if (actmode == mode_e::TARGET) {
for (i = 0; i < count; i++) {
if(i==delay_after_bytes){
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes)
@ -1080,7 +1070,7 @@ void GPIOBUS::MakeTable(void)
int i;
int j;
BOOL tblParity[256];
bool tblParity[256];
#if SIGNAL_CONTROL_MODE == 0
int index;
int shift;
@ -1249,13 +1239,13 @@ void GPIOBUS::SetSignal(int pin, bool ast)
// Wait for signal change
//
//---------------------------------------------------------------------------
bool GPIOBUS::WaitSignal(int pin, BOOL ast)
bool GPIOBUS::WaitSignal(int pin, int ast)
{
// Get current time
DWORD now = SysTimer::GetTimerLow();
uint32_t now = SysTimer::GetTimerLow();
// Calculate timeout (3000ms)
DWORD timeout = 3000 * 1000;
uint32_t timeout = 3000 * 1000;
// end immediately if the signal has changed
do {
@ -1416,15 +1406,15 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
if (GetPinRaw(raw_data, PIN_SEL))
{
if(GetPinRaw(raw_data, PIN_IO)){
return BUS::reselection;
return BUS::phase_t::reselection;
}else{
return BUS::selection;
return BUS::phase_t::selection;
}
}
// Bus busy phase
if (!GetPinRaw(raw_data, PIN_BSY)) {
return BUS::busfree;
return BUS::phase_t::busfree;
}
// Get target phase from bus signal line

View File

@ -308,7 +308,7 @@ public:
GPIOBUS()= default;
~GPIOBUS() final = default;
// Destructor
bool Init(mode_e mode = TARGET) override;
bool Init(mode_e mode = mode_e::TARGET) override;
// Initialization
void Reset() override;
// Reset
@ -320,7 +320,7 @@ public:
// Bus signal acquisition
//
//---------------------------------------------------------------------------
inline DWORD Acquire() override
inline uint32_t Acquire() override
{
#if defined(__x86_64__) || defined(__X86__)
// Only used for development/debugging purposes. Isn't really applicable
@ -429,7 +429,7 @@ private:
// Get SCSI input signal value
void SetSignal(int pin, bool ast) override;
// Set SCSI output signal value
bool WaitSignal(int pin, BOOL ast);
bool WaitSignal(int pin, int ast);
// Wait for a signal to change
// Interrupt control
void DisableIRQ();
@ -448,7 +448,7 @@ private:
// Set GPIO drive strength
mode_e actmode = TARGET; // Operation mode
mode_e actmode = mode_e::TARGET; // Operation mode
uint32_t baseaddr = 0; // Base address

View File

@ -25,14 +25,14 @@
// System timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::systaddr;
volatile uint32_t* SysTimer::systaddr;
//---------------------------------------------------------------------------
//
// ARM timer address
//
//---------------------------------------------------------------------------
volatile DWORD* SysTimer::armtaddr;
volatile uint32_t* SysTimer::armtaddr;
//---------------------------------------------------------------------------
//
@ -46,7 +46,7 @@ volatile DWORD SysTimer::corefreq;
// Initialize the system timer
//
//---------------------------------------------------------------------------
void SysTimer::Init(DWORD *syst, DWORD *armt)
void SysTimer::Init(uint32_t *syst, uint32_t *armt)
{
// RPI Mailbox property interface
// Get max clock rate
@ -59,7 +59,7 @@ void SysTimer::Init(DWORD *syst, DWORD *armt)
//
// Clock id
// 0x000000004: CORE
DWORD maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
uint32_t maxclock[32] = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
// Save the base address
systaddr = syst;
@ -83,7 +83,7 @@ void SysTimer::Init(DWORD *syst, DWORD *armt)
// Get system timer low byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerLow() {
uint32_t SysTimer::GetTimerLow() {
return systaddr[SYST_CLO];
}
@ -92,7 +92,7 @@ DWORD SysTimer::GetTimerLow() {
// Get system timer high byte
//
//---------------------------------------------------------------------------
DWORD SysTimer::GetTimerHigh() {
uint32_t SysTimer::GetTimerHigh() {
return systaddr[SYST_CHI];
}
@ -109,7 +109,7 @@ void SysTimer::SleepNsec(DWORD nsec)
}
// Calculate the timer difference
DWORD diff = corefreq * nsec / 1000;
uint32_t diff = corefreq * nsec / 1000;
// Return if the difference in time is too small
if (diff == 0) {
@ -117,7 +117,7 @@ void SysTimer::SleepNsec(DWORD nsec)
}
// Start
DWORD start = armtaddr[ARMT_FREERUN];
uint32_t start = armtaddr[ARMT_FREERUN];
// Loop until timer has elapsed
while ((armtaddr[ARMT_FREERUN] - start) < diff);
@ -135,6 +135,6 @@ void SysTimer::SleepUsec(DWORD usec)
return;
}
DWORD now = GetTimerLow();
uint32_t now = GetTimerLow();
while ((GetTimerLow() - now) < usec);
}

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2021-2022 Uwe Seimet
//
//---------------------------------------------------------------------------
@ -43,11 +43,15 @@ Localizer::Localizer()
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_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", "Skivbildfilen '%1' används redan av ID %2, LUN %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_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");
@ -78,6 +82,8 @@ Localizer::Localizer()
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat ID %1, LUN %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_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");
@ -118,6 +124,24 @@ Localizer::Localizer()
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_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_LUN, "en", "Invalid LUN %1 (0-%2)");
Add(ERROR_INVALID_LUN, "de", "Ungültige LUN %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_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_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_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_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_READY, "en", "%1 operation denied, %2 isn't ready'");
Add(ERROR_OPERATION_DENIED_READY, "de", "%1-Operation verweigert, %2 ist nicht bereit'");
}
void Localizer::Add(LocalizationKey key, const string& locale, string_view value)
@ -132,29 +156,31 @@ void Localizer::Add(LocalizationKey key, const string& locale, string_view value
}
string Localizer::Localize(LocalizationKey key, const string& locale, const string& arg1, const string& arg2,
const string &arg3)
const string &arg3) const
{
string locale_lower = locale;
transform(locale_lower.begin(), locale_lower.end(), locale_lower.begin(), ::tolower);
unordered_map<LocalizationKey, string> messages = localized_messages[locale_lower];
if (messages.empty()) {
auto it = localized_messages.find(locale_lower);
if (it == localized_messages.end()) {
// Try to fall back to country-indepedent locale (e.g. "en" instead of "en_US")
if (locale_lower.length() > 2) {
messages = localized_messages[locale_lower.substr(0, 2)];
it = localized_messages.find(locale_lower.substr(0, 2));
}
if (messages.empty()) {
messages = localized_messages["en"];
if (it == localized_messages.end()) {
it = localized_messages.find("en");
}
}
assert(!messages.empty());
assert(it != localized_messages.end());
string message = messages[key];
auto messages = it->second;
if (messages.empty()) {
return "Missing localization for enum value " + to_string(key);
}
string message = messages[key];
message = regex_replace(message, regex("%1"), arg1);
message = regex_replace(message, regex("%2"), arg2);
message = regex_replace(message, regex("%3"), arg3);

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2021-2022 Uwe Seimet
//
// Message localization support. Currently only for messages with up to 3 string parameters.
//
@ -23,13 +23,16 @@ enum LocalizationKey {
ERROR_LOG_LEVEL,
ERROR_MISSING_DEVICE_ID,
ERROR_MISSING_FILENAME,
ERROR_DEVICE_MISSING_FILENAME,
ERROR_IMAGE_IN_USE,
ERROR_IMAGE_FILE_INFO,
ERROR_RESERVED_ID,
ERROR_NON_EXISTING_DEVICE,
ERROR_NON_EXISTING_UNIT,
ERROR_UNKNOWN_DEVICE_TYPE,
ERROR_MISSING_DEVICE_TYPE,
ERROR_DUPLICATE_ID,
ERROR_DETACH,
ERROR_EJECT_REQUIRED,
ERROR_DEVICE_NAME_UPDATE,
ERROR_SHUTDOWN_MODE_MISSING,
@ -37,7 +40,16 @@ enum LocalizationKey {
ERROR_SHUTDOWN_PERMISSION,
ERROR_FILE_OPEN,
ERROR_BLOCK_SIZE,
ERROR_BLOCK_SIZE_NOT_CONFIGURABLE
ERROR_BLOCK_SIZE_NOT_CONFIGURABLE,
ERROR_SCSI_CONTROLLER,
ERROR_INVALID_ID,
ERROR_INVALID_LUN,
ERROR_LUN0,
ERROR_INITIALIZATION,
ERROR_OPERATION_DENIED_STOPPABLE,
ERROR_OPERATION_DENIED_REMOVABLE,
ERROR_OPERATION_DENIED_PROTECTABLE,
ERROR_OPERATION_DENIED_READY
};
class Localizer
@ -47,7 +59,7 @@ public:
Localizer();
~Localizer() = default;
string Localize(LocalizationKey, const string&, const string& = "", const string& = "", const string& = "");
string Localize(LocalizationKey, const string&, const string& = "", const string& = "", const string& = "") const;
private:

View File

@ -22,13 +22,13 @@ BUS::phase_t GetPhase(const data_capture *sample)
// Selection Phase
if (GetSel(sample))
{
return BUS::selection;
return BUS::phase_t::selection;
}
// Bus busy phase
if (!GetBsy(sample))
{
return BUS::busfree;
return BUS::phase_t::busfree;
}
// Get target phase from bus signal line

View File

@ -104,7 +104,7 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
bool prev_data_valid = false;
bool curr_data_valid;
DWORD selected_id = 0;
BUS::phase_t prev_phase = BUS::busfree;
BUS::phase_t prev_phase = BUS::phase_t::busfree;
bool close_row = false;
int data_space_count = 0;
bool collapsible_div_active = false;
@ -117,7 +117,7 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
data = &data_capture_array[idx];
curr_data_valid = GetAck(data) && GetReq(data);
BUS::phase_t phase = GetPhase(data);
if (phase == BUS::selection && !GetBsy(data))
if (phase == BUS::phase_t::selection && !GetBsy(data))
{
selected_id = GetData(data);
}

View File

@ -54,7 +54,7 @@ static BYTE prev_value[32] = {0xFF};
extern double ns_per_loop;
static BOOL get_pin_value(DWORD data, int pin)
static BYTE get_pin_value(DWORD data, int pin)
{
return (data >> pin) & 1;
}
@ -77,16 +77,16 @@ static BYTE get_data_field(DWORD data)
static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol)
{
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
if (prev_value[pin] != new_value)
if (prev_value[pin] != (int)new_value)
{
prev_value[pin] = new_value;
prev_value[pin] = (int)new_value;
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
}
}
static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol)
{
BOOL new_value = get_pin_value(data, pin);
BYTE new_value = get_pin_value(data, pin);
if (prev_value[pin] != new_value)
{
prev_value[pin] = new_value;

View File

@ -85,9 +85,8 @@
//
//---------------------------------------------------------------------------
using BYTE = unsigned char;
using WORD =uint16_t;
using WORD = uint16_t;
using DWORD = uint32_t;
using BOOL = int;
using TCHAR = char;
#if !defined(FALSE)

View File

@ -23,7 +23,7 @@ using namespace rascsi_interface;
static const char COMPONENT_SEPARATOR = ':';
static const char KEY_VALUE_SEPARATOR = '=';
Localizer localizer;
const Localizer localizer;
void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& params)
{
@ -114,33 +114,32 @@ void protobuf_util::SerializeMessage(int fd, const google::protobuf::Message& me
void protobuf_util::DeserializeMessage(int fd, google::protobuf::Message& message)
{
// Read the header with the size of the protobuf data
uint8_t header_buf[4];
size_t bytes_read = ReadNBytes(fd, header_buf, sizeof(header_buf));
if (bytes_read < sizeof(header_buf)) {
vector<byte> header_buf(4);
if (ReadBytes(fd, header_buf) < header_buf.size()) {
return;
}
size_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16) + ((int)header_buf[1] << 8) + (int)header_buf[0];
if (size <= 0) {
throw io_exception("Broken protobuf message header");
throw io_exception("Invalid protobuf message header");
}
// Read the binary protobuf data
auto data_buf = make_unique<uint8_t[]>(size);
bytes_read = ReadNBytes(fd, data_buf.get(), size);
if (bytes_read < size) {
vector<byte> data_buf(size);
if (ReadBytes(fd, data_buf) < data_buf.size()) {
throw io_exception("Missing protobuf message data");
}
// Create protobuf message
string data((const char *)data_buf.get(), size);
string data((const char *)data_buf.data(), size);
message.ParseFromString(data);
}
size_t protobuf_util::ReadNBytes(int fd, uint8_t *buf, size_t n)
size_t protobuf_util::ReadBytes(int fd, vector<byte>& buf)
{
size_t offset = 0;
while (offset < n) {
ssize_t len = read(fd, buf + offset, n - offset);
while (offset < buf.size()) {
ssize_t len = read(fd, &buf[offset], buf.size() - offset);
if (len <= 0) {
return len;
}

View File

@ -31,7 +31,7 @@ namespace protobuf_util
void AddParam(PbDeviceDefinition&, const string&, string_view);
void SerializeMessage(int, const google::protobuf::Message&);
void DeserializeMessage(int, google::protobuf::Message&);
size_t ReadNBytes(int, uint8_t *, size_t);
size_t ReadBytes(int, vector<byte>&);
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const string& = "", const string& = "",
const string& = "");
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "",

View File

@ -66,7 +66,7 @@ string current_log_level; // Some versions of spdlog do not support get_log_le
string access_token;
unordered_set<int> reserved_ids;
DeviceFactory& device_factory = DeviceFactory::instance();
ControllerManager&controller_manager = ControllerManager::instance();
ControllerManager controller_manager;
RascsiImage rascsi_image;
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
void DetachAll();
@ -91,7 +91,7 @@ void Banner(int argc, char* argv[])
{
FPRT(stdout,"SCSI Target Emulator RaSCSI Reloaded ");
FPRT(stdout,"version %s (%s, %s)\n",
rascsi_get_version_string(),
rascsi_get_version_string().c_str(),
__DATE__,
__TIME__);
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
@ -370,7 +370,7 @@ string SetReservedIds(string_view ids)
void DetachAll()
{
controller_manager.DeleteAllControllers();
DeviceFactory::instance().DeleteAllDevices();
device_factory.DeleteAllDevices();
FileSupport::UnreserveAll();
LOGINFO("Detached all devices")
@ -387,8 +387,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
}
if (unit >= AbstractController::LUN_MAX) {
return ReturnStatus(context, false, "Invalid unit " + to_string(unit) + " (0-" + to_string(AbstractController::LUN_MAX)
+ ")");
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX));
}
string filename = GetParam(pb_device, "file");
@ -449,7 +448,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (file_support != nullptr && !device->IsRemovable() && filename.empty()) {
device_factory.DeleteDevice(device);
return ReturnStatus(context, false, "Device type " + PbDeviceType_Name(type) + " requires a filename");
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
}
Filepath filepath;
@ -511,8 +510,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!device->Init(params)) {
device_factory.DeleteDevice(device);
return ReturnStatus(context, false, "Initialization of " + PbDeviceType_Name(type) + " device, ID " +to_string(id) +
", unit " +to_string(unit) + " failed");
return ReturnLocalizedError(context, ERROR_INITIALIZATION, PbDeviceType_Name(type), to_string(id), to_string(unit));
}
pthread_mutex_lock(&ctrl_mutex);
@ -520,7 +518,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
if (!controller_manager.CreateScsiController(bus, device)) {
pthread_mutex_unlock(&ctrl_mutex);
return ReturnStatus(context, false, "Couldn't create SCSI controller instance");
return ReturnLocalizedError(context, ERROR_SCSI_CONTROLLER);
}
pthread_mutex_unlock(&ctrl_mutex);
@ -543,7 +541,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 ReturnStatus(context, false, "LUN 0 cannot be detached as long as there is still another LUN");
return ReturnLocalizedError(context, ERROR_LUN0);
}
}
}
@ -563,7 +561,7 @@ bool Detach(const CommandContext& context, PrimaryDevice *device, bool dryRun)
if (!controller_manager.FindController(id)->DeleteDevice(device)) {
pthread_mutex_unlock(&ctrl_mutex);
return ReturnStatus(context, false, "Couldn't detach device");
return ReturnLocalizedError(context, ERROR_DETACH);
}
device_factory.DeleteDevice(device);
pthread_mutex_unlock(&ctrl_mutex);
@ -716,8 +714,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID);
}
if (id >= ControllerManager::DEVICE_MAX) {
return ReturnStatus(context, false, "Invalid device ID " + to_string(id) + " (0-"
+ to_string(ControllerManager::DEVICE_MAX - 1) + ")");
return ReturnLocalizedError(context, ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
}
if (operation == ATTACH && reserved_ids.find(id) != reserved_ids.end()) {
@ -726,7 +723,7 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
// Check the Unit Number
if (unit < 0 || unit >= AbstractController::LUN_MAX) {
return ReturnStatus(context, false, "Invalid unit " + to_string(unit) + " (0-" + to_string(AbstractController::LUN_MAX - 1) + ")");
return ReturnLocalizedError(context, ERROR_INVALID_LUN, to_string(unit), to_string(AbstractController::LUN_MAX - 1));
}
if (operation == ATTACH) {
@ -749,18 +746,18 @@ bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_devi
}
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't stoppable)");
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_STOPPABLE, device->GetType());
}
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't removable)");
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_REMOVABLE, device->GetType());
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't protectable)");
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_PROTECTABLE, device->GetType());
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't ready)");
return ReturnLocalizedError(context, ERROR_OPERATION_DENIED_READY, device->GetType());
}
switch (operation) {
@ -991,8 +988,8 @@ bool ParseArgument(int argc, char* argv[], int& port)
string name;
string log_level;
string locale = setlocale(LC_MESSAGES, "");
if (locale == "C") {
const char *locale = setlocale(LC_MESSAGES, "");
if (locale == nullptr || !strcmp(locale, "C")) {
locale = "en";
}
@ -1211,12 +1208,12 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
}
// Read magic string
char magic[6];
int bytes_read = ReadNBytes(context.fd, (uint8_t *)magic, sizeof(magic));
vector<byte> magic(6);
size_t bytes_read = ReadBytes(context.fd, magic);
if (!bytes_read) {
continue;
}
if (bytes_read != sizeof(magic) || strncmp(magic, "RASCSI", sizeof(magic))) {
if (bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
throw io_exception("Invalid magic");
}
@ -1320,7 +1317,7 @@ static void *MonThread(void *) //NOSONAR The pointer cannot be const void * beca
SerializeMessage(context.fd, result);
}
else {
ReturnStatus(context, false, "Can't get image file info for '" + filename + "'");
ReturnLocalizedError(context, ERROR_IMAGE_FILE_INFO);
}
}
break;
@ -1390,14 +1387,6 @@ int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifndef NDEBUG
// Get temporary operation info, in order to trigger an assertion on startup if the operation list is incomplete
// TODO Move to unit test?
PbResult pb_operation_info_result;
const auto operation_info = unique_ptr<PbOperationInfo>(rascsi_response.GetOperationInfo(pb_operation_info_result, 0));
assert(operation_info->operations_size() == PbOperation_ARRAYSIZE - 1);
#endif
BUS::phase_t phase;
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits.
@ -1463,7 +1452,7 @@ int main(int argc, char* argv[])
// Main Loop
while (running) {
// Work initialization
phase = BUS::busfree;
phase = BUS::phase_t::busfree;
#ifdef USE_SEL_EVENT_ENABLE
// SEL signal polling
@ -1489,7 +1478,7 @@ int main(int argc, char* argv[])
// Wait until BSY is released as there is a possibility for the
// initiator to assert it while setting the ID (for up to 3 seconds)
if (bus->GetBSY()) {
int now = SysTimer::GetTimerLow();
uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus->Acquire();
if (!bus->GetBSY()) {
@ -1515,13 +1504,13 @@ int main(int argc, char* argv[])
if (controller != nullptr) {
initiator_id = controller->ExtractInitiatorId(id_data);
if (controller->Process(initiator_id) == BUS::selection) {
phase = BUS::selection;
if (controller->Process(initiator_id) == BUS::phase_t::selection) {
phase = BUS::phase_t::selection;
}
}
// Return to bus monitoring if the selection phase has not started
if (phase != BUS::selection) {
if (phase != BUS::phase_t::selection) {
pthread_mutex_unlock(&ctrl_mutex);
continue;
}
@ -1541,7 +1530,7 @@ int main(int argc, char* argv[])
phase = controller->Process(initiator_id);
// End when the bus is free
if (phase == BUS::busfree) {
if (phase == BUS::phase_t::busfree) {
break;
}
}

View File

@ -19,9 +19,6 @@
using namespace rascsi_interface;
using namespace protobuf_util;
list<string> RascsiResponse::log_levels = { "trace", "debug", "info", "warn", "err", "critical", "off" };
PbDeviceProperties *RascsiResponse::GetDeviceProperties(const Device *device)
{
auto properties = make_unique<PbDeviceProperties>().release();
@ -350,164 +347,135 @@ PbMappingInfo *RascsiResponse::GetMappingInfo(PbResult& result)
PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth)
{
auto operation_info = make_unique<PbOperationInfo>().release();
auto operation_info = make_unique<PbOperationInfo>();
auto meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "name", "Image file name in case of a mass storage device");
AddOperationParameter(meta_data.get(), "interface", "Comma-separated prioritized network interface list");
AddOperationParameter(meta_data.get(), "inet", "IP address and netmask of the network bridge");
AddOperationParameter(meta_data.get(), "cmd", "Print command for the printer device");
AddOperationParameter(meta_data.get(), "timeout", "Reservation timeout for the printer device in seconds");
CreateOperation(operation_info, meta_data.get(), ATTACH, "Attach device, device-specific parameters are required");
auto operation = CreateOperation(*operation_info, ATTACH, "Attach device, device-specific parameters are required");
AddOperationParameter(*operation, "name", "Image file name in case of a mass storage device");
AddOperationParameter(*operation, "interface", "Comma-separated prioritized network interface list");
AddOperationParameter(*operation, "inet", "IP address and netmask of the network bridge");
AddOperationParameter(*operation, "cmd", "Print command for the printer device");
AddOperationParameter(*operation, "timeout", "Reservation timeout for the printer device in seconds");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), DETACH, "Detach device, device-specific parameters are required");
CreateOperation(*operation_info, DETACH, "Detach device, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), DETACH_ALL, "Detach all devices");
CreateOperation(*operation_info, DETACH_ALL, "Detach all devices");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), START, "Start device, device-specific parameters are required");
CreateOperation(*operation_info, START, "Start device, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), STOP, "Stop device, device-specific parameters are required");
CreateOperation(*operation_info, STOP, "Stop device, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data.get(), INSERT, "Insert medium, device-specific parameters are required");
operation = CreateOperation(*operation_info, INSERT, "Insert medium, device-specific parameters are required");
AddOperationParameter(*operation, "file", "Image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), EJECT, "Eject medium, device-specific parameters are required");
CreateOperation(*operation_info, EJECT, "Eject medium, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), PROTECT, "Protect medium, device-specific parameters are required");
CreateOperation(*operation_info, PROTECT, "Protect medium, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), UNPROTECT, "Unprotect medium, device-specific parameters are required");
CreateOperation(*operation_info, UNPROTECT, "Unprotect medium, device-specific parameters are required");
meta_data = make_unique<PbOperationMetaData>();
operation = CreateOperation(*operation_info, SERVER_INFO, "Get rascsi server information");
if (depth) {
AddOperationParameter(meta_data.get(), "folder_pattern", "Pattern for filtering image folder names");
AddOperationParameter(*operation, "folder_pattern", "Pattern for filtering image folder names");
}
AddOperationParameter(meta_data.get(), "file_pattern", "Pattern for filtering image file names");
CreateOperation(operation_info, meta_data.get(), SERVER_INFO, "Get rascsi server information");
AddOperationParameter(*operation, "file_pattern", "Pattern for filtering image file names");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), VERSION_INFO, "Get rascsi server version");
CreateOperation(*operation_info, VERSION_INFO, "Get rascsi server version");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), DEVICES_INFO, "Get information on attached devices");
CreateOperation(*operation_info, DEVICES_INFO, "Get information on attached devices");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), DEVICE_TYPES_INFO, "Get device properties by device type");
CreateOperation(*operation_info, DEVICE_TYPES_INFO, "Get device properties by device type");
meta_data = make_unique<PbOperationMetaData>();
operation = CreateOperation(*operation_info, DEFAULT_IMAGE_FILES_INFO, "Get information on available image files");
if (depth) {
AddOperationParameter(meta_data.get(), "folder_pattern", "Pattern for filtering image folder names");
AddOperationParameter(*operation, "folder_pattern", "Pattern for filtering image folder names");
}
AddOperationParameter(meta_data.get(), "file_pattern", "Pattern for filtering image file names");
CreateOperation(operation_info, meta_data.get(), DEFAULT_IMAGE_FILES_INFO, "Get information on available image files");
AddOperationParameter(*operation, "file_pattern", "Pattern for filtering image file names");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data.get(), IMAGE_FILE_INFO, "Get information on image file");
operation = CreateOperation(*operation_info, IMAGE_FILE_INFO, "Get information on image file");
AddOperationParameter(*operation, "file", "Image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), LOG_LEVEL_INFO, "Get log level information");
CreateOperation(*operation_info, LOG_LEVEL_INFO, "Get log level information");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), NETWORK_INTERFACES_INFO, "Get the available network interfaces");
CreateOperation(*operation_info, NETWORK_INTERFACES_INFO, "Get the available network interfaces");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), MAPPING_INFO, "Get mapping of extensions to device types");
CreateOperation(*operation_info, MAPPING_INFO, "Get mapping of extensions to device types");
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), RESERVED_IDS_INFO, "Get list of reserved device IDs");
CreateOperation(*operation_info, RESERVED_IDS_INFO, "Get list of reserved device IDs");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "folder", "Default image file folder name", "", true);
CreateOperation(operation_info, meta_data.get(), DEFAULT_FOLDER, "Set default image file folder");
operation = CreateOperation(*operation_info, DEFAULT_FOLDER, "Set default image file folder");
AddOperationParameter(*operation, "folder", "Default image file folder name", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "level", "New log level", "", true);
CreateOperation(operation_info, meta_data.get(), LOG_LEVEL, "Set log level");
operation = CreateOperation(*operation_info, LOG_LEVEL, "Set log level");
AddOperationParameter(*operation, "level", "New log level", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "ids", "Comma-separated device ID list", "", true);
CreateOperation(operation_info, meta_data.get(), RESERVE_IDS, "Reserve device IDs");
operation = CreateOperation(*operation_info, RESERVE_IDS, "Reserve device IDs");
AddOperationParameter(*operation, "ids", "Comma-separated device ID list", "", true);
meta_data = make_unique<PbOperationMetaData>();
PbOperationParameter *parameter = AddOperationParameter(meta_data.get(), "mode", "Shutdown mode", "", true);
operation = CreateOperation(*operation_info, SHUT_DOWN, "Shut down or reboot");
PbOperationParameter *parameter = AddOperationParameter(*operation, "mode", "Shutdown mode", "", true);
parameter->add_permitted_values("rascsi");
// System shutdown/reboot requires root permissions
if (!getuid()) {
parameter->add_permitted_values("system");
parameter->add_permitted_values("reboot");
}
CreateOperation(operation_info, meta_data.get(), SHUT_DOWN, "Shut down or reboot");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
AddOperationParameter(meta_data.get(), "size", "Image file size in bytes", "", true);
parameter = AddOperationParameter(meta_data.get(), "read_only", "Read-only flag", "false");
operation = CreateOperation(*operation_info, CREATE_IMAGE, "Create an image file");
AddOperationParameter(*operation, "file", "Image file name", "", true);
AddOperationParameter(*operation, "size", "Image file size in bytes", "", true);
parameter = AddOperationParameter(*operation, "read_only", "Read-only flag", "false");
parameter->add_permitted_values("true");
parameter->add_permitted_values("false");
CreateOperation(operation_info, meta_data.get(), CREATE_IMAGE, "Create an image file");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data.get(), DELETE_IMAGE, "Delete image file");
operation = CreateOperation(*operation_info, DELETE_IMAGE, "Delete image file");
AddOperationParameter(*operation, "file", "Image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "from", "Source image file name", "", true);
AddOperationParameter(meta_data.get(), "to", "Destination image file name", "", true);
CreateOperation(operation_info, meta_data.get(), RENAME_IMAGE, "Rename image file");
operation = CreateOperation(*operation_info, RENAME_IMAGE, "Rename image file");
AddOperationParameter(*operation, "from", "Source image file name", "", true);
AddOperationParameter(*operation, "to", "Destination image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "from", "Source image file name", "", true);
AddOperationParameter(meta_data.get(), "to", "Destination image file name", "", true);
parameter = AddOperationParameter(meta_data.get(), "read_only", "Read-only flag", "false");
operation = CreateOperation(*operation_info, COPY_IMAGE, "Copy image file");
AddOperationParameter(*operation, "from", "Source image file name", "", true);
AddOperationParameter(*operation, "to", "Destination image file name", "", true);
parameter = AddOperationParameter(*operation, "read_only", "Read-only flag", "false");
parameter->add_permitted_values("true");
parameter->add_permitted_values("false");
CreateOperation(operation_info, meta_data.get(), COPY_IMAGE, "Copy image file");
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data.get(), PROTECT_IMAGE, "Write-protect image file");
operation = CreateOperation(*operation_info, PROTECT_IMAGE, "Write-protect image file");
AddOperationParameter(*operation, "file", "Image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data.get(), UNPROTECT_IMAGE, "Make image file writable");
operation = CreateOperation(*operation_info, UNPROTECT_IMAGE, "Make image file writable");
AddOperationParameter(*operation, "file", "Image file name", "", true);
meta_data = make_unique<PbOperationMetaData>();
AddOperationParameter(meta_data.get(), "token", "Authentication token to be checked", "", true);
CreateOperation(operation_info, meta_data.get(), CHECK_AUTHENTICATION, "Check whether an authentication token is valid");
operation = CreateOperation(*operation_info, CHECK_AUTHENTICATION, "Check whether an authentication token is valid");
AddOperationParameter(*operation, "token", "Authentication token to be checked", "", true);
meta_data = make_unique<PbOperationMetaData>();
CreateOperation(operation_info, meta_data.get(), OPERATION_INFO, "Get operation meta data");
CreateOperation(*operation_info, OPERATION_INFO, "Get operation meta data");
result.set_status(true);
return operation_info;
return operation_info.release();
}
void RascsiResponse::CreateOperation(PbOperationInfo *operation_info, PbOperationMetaData *meta_data,
const PbOperation& operation, const string& description) const
PbOperationMetaData *RascsiResponse::CreateOperation(PbOperationInfo& operation_info, const PbOperation& operation,
const string& description) const
{
auto meta_data = make_unique<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;
(*operation_info.mutable_operations())[ordinal] = *meta_data.release();
return &(*operation_info.mutable_operations())[ordinal];
}
PbOperationParameter *RascsiResponse::AddOperationParameter(PbOperationMetaData *meta_data, const string& name,
PbOperationParameter *RascsiResponse::AddOperationParameter(PbOperationMetaData& meta_data, const string& name,
const string& description, const string& default_value, bool is_mandatory)
{
PbOperationParameter *parameter = meta_data->add_parameters();
auto parameter = unique_ptr<PbOperationParameter>(meta_data.add_parameters());
parameter->set_name(name);
parameter->set_description(description);
parameter->set_default_value(default_value);
parameter->set_is_mandatory(is_mandatory);
return parameter;
return parameter.release();
}

View File

@ -49,7 +49,7 @@ private:
DeviceFactory *device_factory;
const RascsiImage *rascsi_image;
static list<string> log_levels;
const list<string> log_levels = { "trace", "debug", "info", "warn", "err", "critical", "off" };
PbDeviceProperties *GetDeviceProperties(const Device *);
void GetDevice(const Device *, PbDevice *);
@ -57,7 +57,7 @@ private:
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
void GetAvailableImages(PbImageFilesInfo&, string_view, const string&, const string&, const string&, int);
void GetAvailableImages(PbResult& result, PbServerInfo&, const string&, const string&, int);
void CreateOperation(PbOperationInfo *, PbOperationMetaData *, const PbOperation&, const string&) const;
PbOperationParameter *AddOperationParameter(PbOperationMetaData *, const string&, const string&,
PbOperationMetaData *CreateOperation(PbOperationInfo&, const PbOperation&, const string&) const;
PbOperationParameter *AddOperationParameter(PbOperationMetaData&, const string&, const string&,
const string& = "", bool = false);
};

View File

@ -9,37 +9,29 @@
//---------------------------------------------------------------------------
#include "rascsi_version.h"
#include <cstdio>
#include <iomanip>
// The following should be updated for each release
const int rascsi_major_version = 22; // Last two digits of year
const int rascsi_minor_version = 9; // Month
const int rascsi_patch_version = -1; // Patch number - increment for each update
static char rascsi_version_string[30]; // Allow for string up to "XX.XX.XXX" + null character + "development build"
using namespace std;
//---------------------------------------------------------------------------
//
// Get the RaSCSI version string
//
//---------------------------------------------------------------------------
const char* rascsi_get_version_string()
string rascsi_get_version_string()
{
if(rascsi_patch_version < 0)
{
snprintf(rascsi_version_string, sizeof(rascsi_version_string),
"%02d.%02d --DEVELOPMENT BUILD--",
rascsi_major_version,
rascsi_minor_version);
stringstream s;
s << setw(2) << setfill('0') << rascsi_major_version << '.' << setw(2) << setfill('0') << rascsi_minor_version;
if (rascsi_patch_version < 0) {
s << " --DEVELOPMENT BUILD--";
}
else
{
snprintf(rascsi_version_string, sizeof(rascsi_version_string), "%02d.%02d.%d",
rascsi_major_version,
rascsi_minor_version,
rascsi_patch_version);
else {
s << '.' << rascsi_patch_version;
}
return rascsi_version_string;
return s.str();
}

View File

@ -9,13 +9,10 @@
//---------------------------------------------------------------------------
#pragma once
#include <string>
extern const int rascsi_major_version; // Last two digits of year
extern const int rascsi_minor_version; // Month
extern const int rascsi_patch_version; // Patch number
//---------------------------------------------------------------------------
//
// Fetch the version string
//
//---------------------------------------------------------------------------
const char* rascsi_get_version_string();
std::string rascsi_get_version_string();

View File

@ -160,8 +160,8 @@ int main(int argc, char* argv[])
string token;
bool list = false;
string locale = setlocale(LC_MESSAGES, "");
if (locale == "C") {
const char *locale = setlocale(LC_MESSAGES, "");
if (locale == nullptr || !strcmp(locale, "C")) {
locale = "en";
}

View File

@ -65,7 +65,7 @@ bool Banner(int argc, char* argv[])
{
printf("RaSCSI hard disk dump utility ");
printf("version %s (%s, %s)\n",
rascsi_get_version_string(),
rascsi_get_version_string().c_str(),
__DATE__,
__TIME__);
@ -100,7 +100,7 @@ bool Init()
}
// GPIO Initialization
if (!bus.Init(BUS::INITIATOR)) {
if (!bus.Init(BUS::mode_e::INITIATOR)) {
return false;
}
@ -209,10 +209,8 @@ bool ParseArgument(int argc, char* argv[])
//---------------------------------------------------------------------------
bool WaitPhase(BUS::phase_t phase)
{
DWORD now;
// Timeout (3000ms)
now = SysTimer::GetTimerLow();
uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Acquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
@ -278,7 +276,7 @@ bool Command(BYTE *buf, int length)
int count;
// Waiting for Phase
if (!WaitPhase(BUS::command)) {
if (!WaitPhase(BUS::phase_t::command)) {
return false;
}
@ -303,7 +301,7 @@ bool Command(BYTE *buf, int length)
int DataIn(BYTE *buf, int length)
{
// Wait for phase
if (!WaitPhase(BUS::datain)) {
if (!WaitPhase(BUS::phase_t::datain)) {
return -1;
}
@ -319,7 +317,7 @@ int DataIn(BYTE *buf, int length)
int DataOut(BYTE *buf, int length)
{
// Wait for phase
if (!WaitPhase(BUS::dataout)) {
if (!WaitPhase(BUS::phase_t::dataout)) {
return -1;
}
@ -337,7 +335,7 @@ int Status()
BYTE buf[256];
// Wait for phase
if (!WaitPhase(BUS::status)) {
if (!WaitPhase(BUS::phase_t::status)) {
return -2;
}
@ -360,7 +358,7 @@ int MessageIn()
BYTE buf[256];
// Wait for phase
if (!WaitPhase(BUS::msgin)) {
if (!WaitPhase(BUS::phase_t::msgin)) {
return -2;
}
@ -838,9 +836,9 @@ int main(int argc, char* argv[])
// File Open
if (restore) {
omode = Fileio::ReadOnly;
omode = Fileio::OpenMode::ReadOnly;
} else {
omode = Fileio::WriteOnly;
omode = Fileio::OpenMode::WriteOnly;
}
if (!fio.Open(hdsfile.GetPath(), omode)) {
fprintf(stderr, "Error : Can't open hds file\n");
@ -854,9 +852,9 @@ int main(int argc, char* argv[])
BusFree();
// Assert reset signal
bus.SetRST(TRUE);
bus.SetRST(true);
usleep(1000);
bus.SetRST(FALSE);
bus.SetRST(false);
// Start dump
printf("TARGET ID : %d\n", targetid);
@ -953,16 +951,12 @@ int main(int argc, char* argv[])
fflush(stdout);
if (restore) {
if (fio.Read(buffer, dsiz)) {
if (Write10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
continue;
}
if (fio.Read(buffer, dsiz) && Write10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
continue;
}
} else {
if (Read10(targetid, i * duni, duni, dsiz, buffer) >= 0) {
if (fio.Write(buffer, dsiz)) {
continue;
}
if (Read10(targetid, i * duni, duni, dsiz, buffer) >= 0 && fio.Write(buffer, dsiz)) {
continue;
}
}

View File

@ -11,6 +11,8 @@
#include "scsi.h"
using namespace std;
//---------------------------------------------------------------------------
//
// Phase Acquisition
@ -20,12 +22,12 @@ BUS::phase_t BUS::GetPhase()
{
// Selection Phase
if (GetSEL()) {
return selection;
return phase_t::selection;
}
// Bus busy phase
if (!GetBSY()) {
return busfree;
return phase_t::busfree;
}
// Get target phase from bus signal line
@ -41,11 +43,10 @@ BUS::phase_t BUS::GetPhase()
//
//---------------------------------------------------------------------------
const char* BUS::GetPhaseStrRaw(phase_t current_phase){
if(current_phase <= phase_t::reserved){
return phase_str_table[current_phase];
if(current_phase <= phase_t::reserved) {
return phase_str_table[(int)current_phase];
}
else
{
else {
return "INVALID";
}
}
@ -57,16 +58,16 @@ const char* BUS::GetPhaseStrRaw(phase_t current_phase){
// This determines the phase based upon the Msg, C/D and I/O signals.
//
//---------------------------------------------------------------------------
const BUS::phase_t BUS::phase_table[8] = {
// | MSG|C/D|I/O |
dataout, // | 0 | 0 | 0 |
datain, // | 0 | 0 | 1 |
command, // | 0 | 1 | 0 |
status, // | 0 | 1 | 1 |
reserved, // | 1 | 0 | 0 |
reserved, // | 1 | 0 | 1 |
msgout, // | 1 | 1 | 0 |
msgin // | 1 | 1 | 1 |
const array<BUS::phase_t, 8> BUS::phase_table = {
// | MSG|C/D|I/O |
phase_t::dataout, // | 0 | 0 | 0 |
phase_t::datain, // | 0 | 0 | 1 |
phase_t::command, // | 0 | 1 | 0 |
phase_t::status, // | 0 | 1 | 1 |
phase_t::reserved, // | 1 | 0 | 0 |
phase_t::reserved, // | 1 | 0 | 1 |
phase_t::msgout, // | 1 | 1 | 0 |
phase_t::msgin // | 1 | 1 | 1 |
};
@ -76,7 +77,7 @@ const BUS::phase_t BUS::phase_table[8] = {
// This MUST be kept in sync with the phase_t enum type!
//
//---------------------------------------------------------------------------
const char* BUS::phase_str_table[] = {
const array<const char*, 12> BUS::phase_str_table = {
"busfree",
"arbitration",
"selection",

View File

@ -10,7 +10,11 @@
//---------------------------------------------------------------------------
#pragma once
#include "os.h"
#include <array>
using namespace std;
//===========================================================================
//
@ -21,14 +25,14 @@ class BUS
{
public:
// Operation modes definition
enum mode_e {
enum class mode_e {
TARGET = 0,
INITIATOR = 1,
MONITOR = 2,
};
// Phase definitions
enum phase_t : BYTE {
enum class phase_t : BYTE {
busfree,
arbitration,
selection,
@ -97,7 +101,7 @@ public:
virtual void SetDAT(BYTE dat) = 0;
virtual bool GetDP() const = 0; // Get parity signal
virtual DWORD Acquire() = 0;
virtual uint32_t Acquire() = 0;
virtual int CommandHandShake(BYTE *buf) = 0;
virtual int ReceiveHandShake(BYTE *buf, int count) = 0;
virtual int SendHandShake(BYTE *buf, int count, int delay_after_bytes) = 0;
@ -109,13 +113,13 @@ public:
static const int SEND_NO_DELAY = -1;
// Passed into SendHandShake when we don't want to delay
private:
static const phase_t phase_table[8];
static const array<phase_t, 8> phase_table;
static const char* phase_str_table[];
static const array<const char *, 12> phase_str_table;
};
namespace scsi_defs {
enum scsi_level : int {
enum class scsi_level : int {
SCSI_1_CCS = 1,
SCSI_2 = 2,
SPC = 3,
@ -126,7 +130,7 @@ namespace scsi_defs {
SPC_6 = 8
};
enum device_type : int {
enum class device_type : int {
DIRECT_ACCESS = 0,
PRINTER = 2,
PROCESSOR = 3,
@ -135,7 +139,7 @@ namespace scsi_defs {
COMMUNICATIONS = 9
};
enum scsi_command : int {
enum class scsi_command : int {
eCmdTestUnitReady = 0x00,
eCmdRezero = 0x01,
eCmdRequestSense = 0x03,
@ -187,7 +191,7 @@ namespace scsi_defs {
eCmdReportLuns = 0xA0
};
enum status : int {
enum class status : int {
GOOD = 0x00,
CHECK_CONDITION = 0x02,
CONDITION_MET = 0x04,
@ -199,7 +203,7 @@ namespace scsi_defs {
QUEUE_FULL = 0x28
};
enum sense_key : int {
enum class sense_key : int {
NO_SENSE = 0x00,
RECOVERED_ERROR = 0x01,
NOT_READY = 0x02,
@ -217,7 +221,7 @@ namespace scsi_defs {
COMPLETED = 0x0f
};
enum asc : int {
enum class asc : int {
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
WRITE_FAULT = 0x03,
READ_FAULT = 0x11,

View File

@ -113,12 +113,12 @@ void print_copyright_text(int, char *[])
{
LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ")
LOGINFO("version %s (%s, %s)",
rascsi_get_version_string(),
rascsi_get_version_string().c_str(),
__DATE__,
__TIME__)
LOGINFO("Powered by XM6 TypeG Technology ")
LOGINFO("Copyright (C) 2016-2020 GIMONS")
LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project")
LOGINFO("Copyright (C) 2020-2022 Contributors to the RaSCSI project")
LOGINFO(" ")
}
@ -171,15 +171,15 @@ bool Init()
// Interrupt handler settings
if (signal(SIGINT, KillHandler) == SIG_ERR)
{
return FALSE;
return false;
}
if (signal(SIGHUP, KillHandler) == SIG_ERR)
{
return FALSE;
return false;
}
if (signal(SIGTERM, KillHandler) == SIG_ERR)
{
return FALSE;
return false;
}
// GPIO Initialization
@ -335,7 +335,7 @@ int main(int argc, char *argv[])
// Start execution
running = true;
bus->SetACT(FALSE);
bus->SetACT(false);
(void)gettimeofday(&start_time, nullptr);

View File

@ -14,6 +14,7 @@ TEST(ControllerManagerTest, ControllerManager)
{
const int ID = 4;
const int LUN = 6;
ControllerManager controller_manager;
auto device = device_factory.CreateDevice(UNDEFINED, "services", ID);
device->SetId(ID);

View File

@ -18,7 +18,7 @@ public:
TestDevice() : Device("test") {}
~TestDevice() final = default;
bool Dispatch() final { return false; }
bool Dispatch(scsi_defs::scsi_command) final { return false; }
};
TEST(DeviceTest, ProductData)

View File

@ -23,7 +23,7 @@ const unordered_set<uint32_t> sector_sizes;
TEST(ModePagesTest, ModePageDevice_AddModePages)
{
DWORD cdb[6];
vector<int> cdb(6);
BYTE buf[512];
MockModePageDevice device;
@ -38,7 +38,7 @@ TEST(ModePagesTest, ModePageDevice_AddModePages)
TEST(ModePagesTest, SCSIHD_AddModePages)
{
map<int, vector<BYTE>> mode_pages;
map<int, vector<byte>> mode_pages;
MockSCSIHD device(sector_sizes);
device.AddModePages(mode_pages, 0x3f, false);
@ -53,7 +53,7 @@ TEST(ModePagesTest, SCSIHD_AddModePages)
TEST(ModePagesTest, SCSIHD_NEC_AddModePages)
{
map<int, vector<BYTE>> mode_pages;
map<int, vector<byte>> mode_pages;
MockSCSIHD_NEC device;
device.AddModePages(mode_pages, 0x3f, false);
@ -68,7 +68,7 @@ TEST(ModePagesTest, SCSIHD_NEC_AddModePages)
TEST(ModePagesTest, SCSICD_AddModePages)
{
map<int, vector<BYTE>> mode_pages;
map<int, vector<byte>> mode_pages;
MockSCSICD device(sector_sizes);
device.AddModePages(mode_pages, 0x3f, false);
@ -85,7 +85,7 @@ TEST(ModePagesTest, SCSICD_AddModePages)
TEST(ModePagesTest, SCSIMO_AddModePages)
{
map<int, vector<BYTE>> mode_pages;
map<int, vector<byte>> mode_pages;
unordered_map<uint64_t, Geometry> geometries;
MockSCSIMO device(sector_sizes, geometries);
@ -102,7 +102,7 @@ TEST(ModePagesTest, SCSIMO_AddModePages)
TEST(ModePagesTest, HostServices_AddModePages)
{
map<int, vector<BYTE>> mode_pages;
map<int, vector<byte>> mode_pages;
MockHostServices device;
device.AddModePages(mode_pages, 0x3f, false);
@ -115,7 +115,7 @@ TEST(ModePagesTest, ModeSelect)
{
const int LENGTH = 12;
DWORD cdb[16] = {};
vector<int> cdb(16);
BYTE buf[255] = {};
// PF (vendor-specific parameter format)

View File

@ -19,36 +19,37 @@ TEST(PrimaryDeviceTest, UnitReady)
controller.AddDevice(&device);
controller.ctrl.cmd[0] = eCmdTestUnitReady;
controller.ctrl.cmd = vector<int>(6);
controller.ctrl.cmd[0] = (int)scsi_command::eCmdTestUnitReady;
device.SetReset(true);
device.SetAttn(true);
device.SetReady(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
device.SetReset(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
device.SetReset(true);
device.SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
device.SetReset(false);
device.SetAttn(true);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
device.SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
device.SetReady(true);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(device.Dispatch());
EXPECT_TRUE(controller.ctrl.status == scsi_defs::status::GOOD);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdTestUnitReady));
EXPECT_EQ(0, controller.ctrl.status);
}
TEST(PrimaryDeviceTest, Inquiry)
@ -58,7 +59,8 @@ TEST(PrimaryDeviceTest, Inquiry)
device.SetController(&controller);
controller.ctrl.cmd[0] = eCmdInquiry;
controller.ctrl.cmd = vector<int>(6);
controller.ctrl.cmd[0] = (int)scsi_command::eCmdInquiry;
// ALLOCATION LENGTH
controller.ctrl.cmd[4] = 255;
@ -67,18 +69,18 @@ TEST(PrimaryDeviceTest, Inquiry)
});
EXPECT_CALL(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch());
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdInquiry));
EXPECT_EQ(0x7F, controller.ctrl.buffer[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());
EXPECT_EQ(device_type::PROCESSOR, controller.ctrl.buffer[0]);
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, controller.ctrl.buffer[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_2, controller.ctrl.buffer[3]) << "Wrong response level";
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";
ON_CALL(device, InquiryInternal()).WillByDefault([&device]() {
@ -86,20 +88,20 @@ TEST(PrimaryDeviceTest, Inquiry)
});
EXPECT_CALL(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch());
EXPECT_EQ(device_type::DIRECT_ACCESS, controller.ctrl.buffer[0]);
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, controller.ctrl.buffer[2]) << "Wrong SCSI level";
EXPECT_EQ(scsi_level::SCSI_1_CCS, controller.ctrl.buffer[3]) << "Wrong response level";
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";
controller.ctrl.cmd[1] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception) << "EVPD bit is not supported";
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported";
controller.ctrl.cmd[2] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device.Dispatch(), scsi_error_exception) << "PAGE CODE field is not supported";
EXPECT_THROW(device.Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
controller.ctrl.cmd[1] = 0x00;
controller.ctrl.cmd[2] = 0x00;
@ -107,7 +109,7 @@ TEST(PrimaryDeviceTest, Inquiry)
controller.ctrl.cmd[4] = 1;
EXPECT_CALL(device, InquiryInternal()).Times(1);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch());
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";
}
@ -119,17 +121,18 @@ TEST(PrimaryDeviceTest, RequestSense)
controller.AddDevice(&device);
controller.ctrl.cmd[0] = eCmdRequestSense;
controller.ctrl.cmd = vector<int>(6);
controller.ctrl.cmd[0] = (int)scsi_command::eCmdRequestSense;
// ALLOCATION LENGTH
controller.ctrl.cmd[4] = 255;
device.SetReady(false);
EXPECT_THROW(device.Dispatch(), scsi_error_exception);
EXPECT_THROW(device.Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
device.SetReady(true);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device.Dispatch());
EXPECT_TRUE(controller.ctrl.status == scsi_defs::status::GOOD);
EXPECT_TRUE(device.Dispatch(scsi_command::eCmdRequestSense));
EXPECT_EQ(0, controller.ctrl.status);
}
TEST(PrimaryDeviceTest, ReportLuns)
@ -148,12 +151,13 @@ TEST(PrimaryDeviceTest, ReportLuns)
controller.AddDevice(&device2);
ASSERT_TRUE(controller.HasDeviceForLun(LUN2));
controller.ctrl.cmd[0] = eCmdReportLuns;
controller.ctrl.cmd = vector<int>(10);
controller.ctrl.cmd[0] = (int)scsi_command::eCmdReportLuns;
// ALLOCATION LENGTH
controller.ctrl.cmd[9] = 255;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device1.Dispatch());
EXPECT_TRUE(device1.Dispatch(scsi_command::eCmdReportLuns));
const BYTE *buffer = controller.ctrl.buffer;
EXPECT_EQ(0x00, buffer[0]) << "Wrong data length";
EXPECT_EQ(0x00, buffer[1]) << "Wrong data length";
@ -177,7 +181,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
controller.ctrl.cmd[2] = 0x01;
EXPECT_THROW(device1.Dispatch(), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
EXPECT_THROW(device1.Dispatch(scsi_command::eCmdReportLuns), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
}
TEST(PrimaryDeviceTest, UnknownCommand)
@ -187,6 +191,7 @@ TEST(PrimaryDeviceTest, UnknownCommand)
controller.AddDevice(&device);
controller.ctrl.cmd = vector<int>(1);
controller.ctrl.cmd[0] = 0xFF;
EXPECT_FALSE(device.Dispatch());
EXPECT_FALSE(device.Dispatch((scsi_command)0xFF));
}

View File

@ -0,0 +1,25 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "testing.h"
#include "rascsi_interface.pb.h"
#include "rascsi_response.h"
#include "rascsi_image.h"
using namespace rascsi_interface;
TEST(ResponseTest, Operation_Count)
{
RascsiImage rascsi_image;
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
PbResult pb_operation_info_result;
const auto operation_info = unique_ptr<PbOperationInfo>(rascsi_response.GetOperationInfo(pb_operation_info_result, 0));
EXPECT_EQ(PbOperation_ARRAYSIZE - 1, operation_info->operations_size());
}

View File

@ -0,0 +1,45 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "testing.h"
#include "devices/scsi_command_util.h"
TEST(ScsiCommandUtilTest, EnrichFormatPage)
{
const int SECTOR_SIZE = 512;
map<int, vector<byte>> pages;
vector<byte> format_page(24);
pages[3] = format_page;
scsi_command_util::EnrichFormatPage(pages, false, SECTOR_SIZE);
format_page = pages[3];
EXPECT_EQ(byte{0}, format_page[12]);
EXPECT_EQ(byte{0}, format_page[13]);
scsi_command_util::EnrichFormatPage(pages, true, SECTOR_SIZE);
format_page = pages[3];
EXPECT_EQ(byte{SECTOR_SIZE >> 8}, format_page[12]);
EXPECT_EQ(byte{0}, format_page[13]);
}
TEST(ScsiCommandUtilTest, AddAppleVendorModePage)
{
map<int, vector<byte>> pages;
vector<byte> vendor_page(30);
pages[48] = vendor_page;
scsi_command_util::AddAppleVendorModePage(pages, true);
vendor_page = pages[48];
EXPECT_EQ(byte{0}, vendor_page[2]);
scsi_command_util::AddAppleVendorModePage(pages, false);
vendor_page = pages[48];
EXPECT_STREQ("APPLE COMPUTER, INC ", (const char *)&vendor_page[2]);
}

View File

@ -24,9 +24,7 @@ public:
void SetUp() override { spdlog::set_level(spdlog::level::off); }
};
DeviceFactory& device_factory = DeviceFactory::instance();
ControllerManager& controller_manager = ControllerManager::instance();
const DeviceFactory& device_factory = DeviceFactory::instance();
int main(int, char*[])
{

View File

@ -23,7 +23,6 @@
// Note that these global variables are convenient,
// but might cause issues because they are reused by all tests
extern DeviceFactory& device_factory;
extern ControllerManager& controller_manager;
class MockAbstractController : public AbstractController
{
@ -104,7 +103,7 @@ class MockPrimaryDevice : public PrimaryDevice
{
public:
MOCK_METHOD(vector<BYTE>, InquiryInternal, (), (const));
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
MockPrimaryDevice() : PrimaryDevice("test") {}
~MockPrimaryDevice() final = default;
@ -114,7 +113,7 @@ public:
void SetReady(bool ready) { PrimaryDevice::SetReady(ready); }
void SetReset(bool reset) { PrimaryDevice::SetReset(reset); }
void SetAttn(bool attn) { PrimaryDevice::SetAttn(attn); }
vector<BYTE> HandleInquiry(device_type type, scsi_level level, bool is_removable) const {
vector<byte> HandleInquiry(device_type type, scsi_level level, bool is_removable) const {
return PrimaryDevice::HandleInquiry(type, level, is_removable);
}
};
@ -126,22 +125,20 @@ public:
MockModePageDevice() : ModePageDevice("test") {}
~MockModePageDevice() final = default;
MOCK_METHOD(vector<BYTE>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (const DWORD *, BYTE *, int), ());
MOCK_METHOD(int, ModeSense10, (const DWORD *, BYTE *, int), ());
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));
void AddModePages(map<int, vector<BYTE>>& pages, int page, bool) const override {
void AddModePages(map<int, vector<byte>>& pages, int page, bool) const override {
// Return dummy data for other pages than page 0
if (page) {
vector<BYTE> buf(255);
vector<byte> buf(255);
pages[page] = buf;
}
}
// Make protected methods visible for testing
// TODO Why does FRIEND_TEST not work for this method?
int AddModePages(const DWORD *cdb, BYTE *buf, int max_length) const {
// Make protected method visible for testing
int AddModePages(const vector<int>& cdb, BYTE *buf, int max_length) const {
return ModePageDevice::AddModePages(cdb, buf, max_length);
}
};
@ -154,7 +151,7 @@ class MockSCSIHD : public SCSIHD
~MockSCSIHD() final = default;
};
class MockSCSIHD_NEC : public SCSIHD_NEC
class MockSCSIHD_NEC : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
{
FRIEND_TEST(ModePagesTest, SCSIHD_NEC_AddModePages);
@ -183,6 +180,8 @@ class MockHostServices : public HostServices
{
FRIEND_TEST(ModePagesTest, HostServices_AddModePages);
MockHostServices() = default;
public:
MockHostServices() : HostServices(&DeviceFactory::instance()) {}
~MockHostServices() final = default;
};