diff --git a/cpp/controllers/abstract_controller.cpp b/cpp/controllers/abstract_controller.cpp index b2e6d9b4..b113cc9c 100644 --- a/cpp/controllers/abstract_controller.cpp +++ b/cpp/controllers/abstract_controller.cpp @@ -7,7 +7,6 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "devices/primary_device.h" #include "abstract_controller.h" @@ -104,7 +103,6 @@ void AbstractController::ProcessPhase() break; default: - LOGERROR("Cannot process phase %s", BUS::GetPhaseStrRaw(GetPhase())) throw scsi_exception(sense_key::ABORTED_COMMAND); break; } @@ -136,7 +134,7 @@ bool AbstractController::HasDeviceForLun(int lun) const int AbstractController::ExtractInitiatorId(int id_data) const { - int initiator_id = -1; + int initiator_id = UNKNOWN_INITIATOR_ID; if (int tmp = id_data - (1 << target_id); tmp) { initiator_id = 0; diff --git a/cpp/controllers/abstract_controller.h b/cpp/controllers/abstract_controller.h index 587fdadd..3e282225 100644 --- a/cpp/controllers/abstract_controller.h +++ b/cpp/controllers/abstract_controller.h @@ -28,6 +28,8 @@ class AbstractController : public PhaseHandler, public enable_shared_from_this controller_manager, int target_id) : AbstractController(controller_manager, target_id, LUN_MAX) { + logger.SetIdAndLun(target_id, -1); + // The initial buffer size will default to either the default buffer size OR // the size of an Ethernet message, whichever is larger. AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN)); @@ -55,7 +57,7 @@ BUS::phase_t ScsiController::Process(int id) GetBus().Acquire(); if (GetBus().GetRST()) { - LOGWARN("RESET signal received!") + logger.Warn("RESET signal received!"); Reset(); @@ -64,13 +66,6 @@ BUS::phase_t ScsiController::Process(int id) return GetPhase(); } - if (id != UNKNOWN_INITIATOR_ID) { - LOGTRACE("%s Initiator ID is %d", __PRETTY_FUNCTION__, id) - } - else { - LOGTRACE("%s Initiator ID is unknown", __PRETTY_FUNCTION__) - } - initiator_id = id; try { @@ -78,7 +73,7 @@ BUS::phase_t ScsiController::Process(int id) } catch(const scsi_exception&) { // Any exception should have been handled during the phase processing - LOGERROR("%s Unhandled SCSI error, resetting controller and bus and entering bus free phase", __PRETTY_FUNCTION__) + logger.Error("Unhandled SCSI error, resetting controller and bus and entering bus free phase"); Reset(); GetBus().Reset(); @@ -92,7 +87,7 @@ BUS::phase_t ScsiController::Process(int id) void ScsiController::BusFree() { if (!IsBusFree()) { - LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__) + logger.Trace("Bus free phase"); SetPhase(BUS::phase_t::busfree); @@ -124,21 +119,21 @@ void ScsiController::BusFree() // This code has to be executed in the bus free phase and thus has to be located in the controller. switch(shutdown_mode) { case rascsi_shutdown_mode::STOP_RASCSI: - LOGINFO("RaSCSI shutdown requested") + logger.Info("RaSCSI shutdown requested"); exit(EXIT_SUCCESS); break; case rascsi_shutdown_mode::STOP_PI: - LOGINFO("Raspberry Pi shutdown requested") + logger.Info("Raspberry Pi shutdown requested"); if (system("init 0") == -1) { - LOGERROR("Raspberry Pi shutdown failed: %s", strerror(errno)) + logger.Error("Raspberry Pi shutdown failed: " + string(strerror(errno))); } break; case rascsi_shutdown_mode::RESTART_PI: - LOGINFO("Raspberry Pi restart requested") + logger.Info("Raspberry Pi restart requested"); if (system("init 6") == -1) { - LOGERROR("Raspberry Pi restart failed: %s", strerror(errno)) + logger.Error("Raspberry Pi restart failed: " + string(strerror(errno))); } break; @@ -168,7 +163,7 @@ void ScsiController::Selection() return; } - LOGTRACE("%s Selection Phase Target ID=%d", __PRETTY_FUNCTION__, GetTargetId()) + logger.Trace("Selection phase"); SetPhase(BUS::phase_t::selection); @@ -191,7 +186,7 @@ void ScsiController::Selection() void ScsiController::Command() { if (!IsCommand()) { - LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__) + logger.Trace("Command phase"); SetPhase(BUS::phase_t::command); @@ -201,7 +196,9 @@ void ScsiController::Command() const int actual_count = GetBus().CommandHandShake(GetBuffer()); if (actual_count == 0) { - LOGTRACE("ID %d LUN %d received unknown command: $%02X", GetTargetId(), GetEffectiveLun(), GetBuffer()[0]) + stringstream s; + s << "Received unknown command: $" << setfill('0') << setw(2) << hex << GetBuffer()[0]; + logger.Trace(s.str()); Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE); return; @@ -211,21 +208,19 @@ void ScsiController::Command() // If not able to receive all, move to the status phase if (actual_count != command_byte_count) { - LOGERROR("Command byte count mismatch for command $%02X: expected %d bytes, received %d byte(s)", - GetBuffer()[0], command_byte_count, actual_count) + stringstream s; + s << "Command byte count mismatch for command $" << setfill('0') << setw(2) << hex << GetBuffer()[0]; + logger.Error(s.str() + ": expected " + to_string(command_byte_count) + " bytes, received" + + to_string(actual_count) + " byte(s)"); Error(sense_key::ABORTED_COMMAND); return; } - AllocateCmd(command_byte_count); - // Command data transfer - stringstream s; + AllocateCmd(command_byte_count); for (int i = 0; i < command_byte_count; i++) { GetCmd()[i] = GetBuffer()[i]; - s << setfill('0') << setw(2) << hex << GetCmd(i); } - LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str()) SetLength(0); @@ -235,7 +230,13 @@ void ScsiController::Command() void ScsiController::Execute() { - LOGDEBUG("++++ CMD ++++ Executing command $%02X", static_cast(GetOpcode())) + stringstream s; + s << "Controller is executing " << command_mapping.find(GetOpcode())->second.second << ", CDB $" + << setfill('0') << hex; + for (int i = 0; i < BUS::GetCommandByteCount(static_cast(GetOpcode())); i++) { + s << setw(2) << GetCmd(i); + } + logger.Debug(s.str()); // Initialization for data transfer ResetOffset(); @@ -250,7 +251,7 @@ void ScsiController::Execute() int lun = GetEffectiveLun(); if (!HasDeviceForLun(lun)) { if (GetOpcode() != scsi_command::eCmdInquiry && GetOpcode() != scsi_command::eCmdRequestSense) { - LOGTRACE("Invalid LUN %d for device ID %d", lun, GetTargetId()) + logger.Trace("Invalid LUN " + to_string(lun)); Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN); @@ -264,7 +265,7 @@ void ScsiController::Execute() // SCSI-2 4.4.3 Incorrect logical unit handling if (GetOpcode() == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) { - LOGTRACE("Reporting LUN %d for device ID %d as not supported", GetEffectiveLun(), GetTargetId()) + logger.Trace("Reporting LUN" + to_string(GetEffectiveLun()) + " as not supported"); GetBuffer().data()[0] = 0x7f; @@ -295,13 +296,16 @@ void ScsiController::Status() { if (!IsStatus()) { // Minimum execution time + // TODO Why is a delay needed? Is this covered by the SCSI specification? if (execstart > 0) { Sleep(); } else { SysTimer::SleepUsec(5); } - LOGTRACE("%s Status Phase, status is $%02X",__PRETTY_FUNCTION__, static_cast(GetStatus())) + stringstream s; + s << "Status Phase, status is $" << setfill('0') << setw(2) << hex << static_cast(GetStatus()); + logger.Trace(s.str()); SetPhase(BUS::phase_t::status); @@ -325,7 +329,7 @@ void ScsiController::Status() void ScsiController::MsgIn() { if (!IsMsgIn()) { - LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__) + logger.Trace("Message In phase"); SetPhase(BUS::phase_t::msgin); @@ -342,10 +346,8 @@ void ScsiController::MsgIn() void ScsiController::MsgOut() { - LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId()) - if (!IsMsgOut()) { - LOGTRACE("Message Out Phase") + logger.Trace("Message Out phase"); // process the IDENTIFY message if (IsSelection()) { @@ -385,7 +387,7 @@ void ScsiController::DataIn() return; } - LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__) + logger.Trace("Entering Data In phase"); SetPhase(BUS::phase_t::datain); @@ -415,7 +417,7 @@ void ScsiController::DataOut() return; } - LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__) + logger.Trace("Data Out phase"); SetPhase(BUS::phase_t::dataout); @@ -453,7 +455,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status) int lun = GetEffectiveLun(); if (!HasDeviceForLun(lun) || asc == asc::INVALID_LUN) { if (!HasDeviceForLun(0)) { - LOGERROR("No LUN 0 for device %d", GetTargetId()) + logger.Error("No LUN 0"); SetStatus(status); SetMessage(0x00); @@ -467,7 +469,10 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status) } if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) { - LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X", static_cast(sense_key), static_cast(asc)) + stringstream s; + s << setfill('0') << setw(2) << hex << "Error status: Sense Key $" << static_cast(sense_key) + << ", ASC $" << static_cast(asc); + logger.Debug(s.str()); // Set Sense Key and ASC for a subsequent REQUEST SENSE GetDeviceForLun(lun)->SetStatusCode((static_cast(sense_key) << 16) | (static_cast(asc) << 8)); @@ -476,7 +481,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status) SetStatus(status); SetMessage(0x00); - LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__) + logger.Trace("Error (to status phase)"); Status(); } @@ -487,8 +492,7 @@ void ScsiController::Send() assert(GetBus().GetIO()); if (HasValidLength()) { - LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(GetOffset()) + ", length " - + to_string(GetLength())).c_str()) + logger.Trace("Sending data, offset: " + to_string(GetOffset()) + ", length: " + to_string(GetLength())); // The delay should be taken from the respective LUN, but as there are no Daynaport drivers for // LUNs other than 0 this work-around works. @@ -505,7 +509,6 @@ void ScsiController::Send() return; } - // Block subtraction, result initialization DecrementBlocks(); bool result = true; @@ -513,7 +516,7 @@ void ScsiController::Send() if (IsDataIn() && GetBlocks() != 0) { // set next buffer (set offset, length) result = XferIn(GetBuffer()); - LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Processing after data collection. Blocks: " + to_string(GetBlocks())).c_str()) + logger.Trace("Processing after data collection. Blocks: " + to_string(GetBlocks())); } // If result FALSE, move to status phase @@ -524,14 +527,14 @@ void ScsiController::Send() // Continue sending if block !=0 if (GetBlocks() != 0){ - LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Continuing to send. Blocks: " + to_string(GetBlocks())).c_str()) + logger.Trace("Continuing to send. Blocks: " + to_string(GetBlocks())); assert(HasValidLength()); assert(GetOffset() == 0); return; } // Move to next phase - LOGTRACE("%s Move to next phase: %s", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase())) + logger.Trace("Moving to next phase: " + string(BUS::GetPhaseStrRaw(GetPhase()))); switch (GetPhase()) { // Message in phase case BUS::phase_t::msgin: @@ -571,40 +574,36 @@ void ScsiController::Send() void ScsiController::Receive() { + assert(!GetBus().GetREQ()); + assert(!GetBus().GetIO()); + + if (HasValidLength()) { + logger.Trace("Receiving data, transfer length: " + to_string(GetLength()) + " byte(s)"); + + // If not able to receive all, move to status phase + if (uint32_t len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); len != GetLength()) { + logger.Error("Not able to receive " + to_string(GetLength()) + " byte(s) of data, only received " + + to_string(len)); + Error(sense_key::ABORTED_COMMAND); + return; + } + } + if (IsByteTransfer()) { ReceiveBytes(); return; } - LOGTRACE("%s",__PRETTY_FUNCTION__) - - // REQ is low - assert(!GetBus().GetREQ()); - assert(!GetBus().GetIO()); - - // Length != 0 if received if (HasValidLength()) { - LOGTRACE("%s Length is %d byte(s)", __PRETTY_FUNCTION__, GetLength()) - - // If not able to receive all, move to status phase - if (int len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); - len != static_cast(GetLength())) { - LOGERROR("%s Not able to receive %d byte(s) of data, only received %d",__PRETTY_FUNCTION__, GetLength(), len) - Error(sense_key::ABORTED_COMMAND); - return; - } - UpdateOffsetAndLength(); - return; } - // Block subtraction, result initialization DecrementBlocks(); bool result = true; // Processing after receiving data (by phase) - LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase())) + logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase()))); switch (GetPhase()) { case BUS::phase_t::dataout: if (GetBlocks() == 0) { @@ -684,32 +683,16 @@ bool ScsiController::XferMsg(int msg) void ScsiController::ReceiveBytes() { - assert(!GetBus().GetREQ()); - assert(!GetBus().GetIO()); - if (HasValidLength()) { - LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, GetLength()) - - // If not able to receive all, move to status phase - if (uint32_t len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); len != GetLength()) { - LOGERROR("%s Not able to receive %d byte(s) of data, only received %d", - __PRETTY_FUNCTION__, GetLength(), len) - Error(sense_key::ABORTED_COMMAND); - return; - } - SetBytesToTransfer(GetLength()); - UpdateOffsetAndLength(); - return; } - // Result initialization bool result = true; // Processing after receiving data (by phase) - LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase())) + logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase()))); switch (GetPhase()) { case BUS::phase_t::dataout: result = XferOut(false); @@ -804,7 +787,10 @@ void ScsiController::DataOutNonBlockOriented() break; default: - LOGWARN("Unexpected Data Out phase for command $%02X", static_cast(GetOpcode())) + stringstream s; + s << "Unexpected Data Out phase for command $" << setfill('0') << setw(2) << hex + << static_cast(GetOpcode()); + logger.Warn(s.str()); break; } } @@ -819,7 +805,9 @@ bool ScsiController::XferIn(vector& buf) { assert(IsDataIn()); - LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, static_cast(GetOpcode())) + stringstream s; + s << "Command: $" << setfill('0') << setw(2) << hex << static_cast(GetOpcode()); + logger.Trace(s.str()); int lun = GetEffectiveLun(); if (!HasDeviceForLun(lun)) { @@ -930,11 +918,14 @@ bool ScsiController::XferOutBlockOriented(bool cont) } case scsi_command::eCmdSetMcastAddr: - LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__) + logger.Trace("Done with DaynaPort Set Multicast Address"); break; default: - LOGWARN("Received an unexpected command ($%02X) in %s", static_cast(GetOpcode()), __PRETTY_FUNCTION__) + stringstream s; + s << "Received an unexpected command ($" << setfill('0') << setw(2) << hex + << static_cast(GetOpcode()) << ")"; + logger.Warn(s.str()); break; } @@ -946,12 +937,12 @@ void ScsiController::ProcessCommand() uint32_t len = GPIOBUS::GetCommandByteCount(GetBuffer()[0]); stringstream s; - s << setfill('0') << setw(2) << hex; + s << "CDB=$" << setfill('0') << setw(2) << hex; for (uint32_t i = 0; i < len; i++) { GetCmd()[i] = GetBuffer()[i]; s << GetCmd(i); } - LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str()) + logger.Trace(s.str()); Execute(); } @@ -963,13 +954,13 @@ void ScsiController::ParseMessage() const uint8_t message_type = scsi.msb[i]; if (message_type == 0x06) { - LOGTRACE("Received ABORT message") + logger.Trace("Received ABORT message"); BusFree(); return; } if (message_type == 0x0C) { - LOGTRACE("Received BUS DEVICE RESET message") + logger.Trace("Received BUS DEVICE RESET message"); scsi.syncoffset = 0; if (auto device = GetDeviceForLun(identified_lun); device != nullptr) { device->DiscardReservation(); @@ -980,11 +971,11 @@ void ScsiController::ParseMessage() if (message_type >= 0x80) { identified_lun = static_cast(message_type) & 0x1F; - LOGTRACE("Received IDENTIFY message for LUN %d", identified_lun) + logger.Trace("Received IDENTIFY message for LUN " + to_string(identified_lun)); } if (message_type == 0x01) { - LOGTRACE("Received EXTENDED MESSAGE") + logger.Trace("Received EXTENDED MESSAGE"); // Check only when synchronous transfer is possible if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) { diff --git a/cpp/controllers/scsi_controller.h b/cpp/controllers/scsi_controller.h index 502d9bf7..11fa3128 100644 --- a/cpp/controllers/scsi_controller.h +++ b/cpp/controllers/scsi_controller.h @@ -16,6 +16,7 @@ #include "shared/scsi.h" #include "controller_manager.h" +#include "devices/device_logger.h" #include "abstract_controller.h" #include @@ -34,8 +35,6 @@ class ScsiController : public AbstractController // REQ/ACK offset(limited to 16) static const uint8_t MAX_SYNC_OFFSET = 16; - static const int UNKNOWN_INITIATOR_ID = -1; - const int DEFAULT_BUFFER_SIZE = 0x1000; using scsi_t = struct _scsi_t { @@ -88,6 +87,8 @@ public: private: + DeviceLogger logger; + // Execution start time uint32_t execstart = 0; diff --git a/cpp/devices/device.cpp b/cpp/devices/device.cpp index c30343a3..b692b57c 100644 --- a/cpp/devices/device.cpp +++ b/cpp/devices/device.cpp @@ -7,7 +7,6 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_version.h" #include "device.h" #include diff --git a/cpp/devices/device.h b/cpp/devices/device.h index 1decf11a..1d554bf9 100644 --- a/cpp/devices/device.h +++ b/cpp/devices/device.h @@ -9,6 +9,7 @@ #pragma once +#include "shared/log.h" #include "generated/rascsi_interface.pb.h" #include #include @@ -72,6 +73,8 @@ class Device //NOSONAR The number of fields and methods is justified, the comple protected: + Device(PbDeviceType, int); + void SetReady(bool b) { ready = b; } bool IsReset() const { return reset; } void SetReset(bool b) { reset = b; } @@ -89,8 +92,6 @@ protected: string GetParam(const string&) const; void SetParams(const unordered_map&); - Device(PbDeviceType, int); - public: virtual ~Device() = default; diff --git a/cpp/devices/device_logger.cpp b/cpp/devices/device_logger.cpp new file mode 100644 index 00000000..2fc739b9 --- /dev/null +++ b/cpp/devices/device_logger.cpp @@ -0,0 +1,75 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI Reloaded +// for Raspberry Pi +// +// Copyright (C) 2022 Uwe Seimet +// +//--------------------------------------------------------------------------- + +#include "shared/log.h" +#include "device_logger.h" + +using namespace std; + +void DeviceLogger::Trace(const string& message) const +{ + if (const string m = GetLogMessage(message); !m.empty()) { + LOGTRACE("%s", m.c_str()) + } +} + +void DeviceLogger::Debug(const string& message) const +{ + if (const string m = GetLogMessage(message); !m.empty()) { + LOGDEBUG("%s", m.c_str()) + } +} + +void DeviceLogger::Info(const string& message) const +{ + if (const string m = GetLogMessage(message); !m.empty()) { + LOGINFO("%s", m.c_str()) + } +} + +void DeviceLogger::Warn(const string& message) const +{ + if (const string m = GetLogMessage(message); !m.empty()) { + LOGWARN("%s", m.c_str()) + } +} + +void DeviceLogger::Error(const string& message) const +{ + if (const string m = GetLogMessage(message); !m.empty()) { + LOGERROR("%s", m.c_str()) + } +} + +string DeviceLogger::GetLogMessage(const string& message) const +{ + if (log_device_id == -1 || (log_device_id == id && (log_device_lun == -1 || log_device_lun == lun))) + { + if (lun == -1) { + return "(ID " + to_string(id) + ") - " + message; + } + else { + return "(ID:LUN " + to_string(id) + ":" + to_string(lun) + ") - " + message; + } + } + + return ""; +} + +void DeviceLogger::SetIdAndLun(int i, int l) +{ + id = i; + lun = l; +} + +void DeviceLogger::SetLogIdAndLun(int i, int l) +{ + log_device_id = i; + log_device_lun = l; +} diff --git a/cpp/devices/device_logger.h b/cpp/devices/device_logger.h new file mode 100644 index 00000000..0f699b73 --- /dev/null +++ b/cpp/devices/device_logger.h @@ -0,0 +1,44 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI Reloaded +// for Raspberry Pi +// +// Copyright (C) 2022 Uwe Seimet +// +//--------------------------------------------------------------------------- + +#pragma once + +#include + +using namespace std; + +class DeviceLogger +{ + +public: + + DeviceLogger() = default; + ~DeviceLogger() = default; + + void Trace(const string&) const; + void Debug(const string&) const; + void Info(const string&) const; + void Warn(const string&) const; + void Error(const string&) const; + + string GetLogMessage(const string&) const; + + void SetIdAndLun(int, int); + + static void SetLogIdAndLun(int, int); + +private: + + int id = -1; + int lun = -1; + + // TODO Try to only have one shared instance, so that these fields do not have to be static + static inline int log_device_id = -1; + static inline int log_device_lun = -1; +}; diff --git a/cpp/devices/disk.cpp b/cpp/devices/disk.cpp index 5db92dab..3e2c906e 100644 --- a/cpp/devices/disk.cpp +++ b/cpp/devices/disk.cpp @@ -14,10 +14,11 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "disk.h" +#include +#include using namespace scsi_defs; using namespace scsi_command_util; @@ -116,7 +117,7 @@ void Disk::Read(access_mode mode) GetController()->SetBlocks(blocks); GetController()->SetLength(Read(GetController()->GetCmd(), GetController()->GetBuffer(), start)); - LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, GetController()->GetLength()) + GetLogger().Trace("Length is " + to_string(GetController()->GetLength())); // Set next block GetController()->SetNext(start + 1); @@ -203,10 +204,10 @@ void Disk::StartStopUnit() const bool load = GetController()->GetCmd(4) & 0x02; if (load) { - LOGTRACE(start ? "Loading medium" : "Ejecting medium") + GetLogger().Trace(start ? "Loading medium" : "Ejecting medium"); } else { - LOGTRACE(start ? "Starting unit" : "Stopping unit") + GetLogger().Trace(start ? "Starting unit" : "Stopping unit"); SetStopped(!start); } @@ -238,7 +239,7 @@ void Disk::PreventAllowMediumRemoval() const bool lock = GetController()->GetCmd(4) & 0x01; - LOGTRACE(lock ? "Locking medium" : "Unlocking medium") + GetLogger().Trace(lock ? "Locking medium" : "Unlocking medium"); SetLocked(lock); @@ -618,8 +619,8 @@ void Disk::ValidateBlockAddress(access_mode mode) const const uint64_t block = mode == RW16 ? GetInt64(GetController()->GetCmd(), 2) : GetInt32(GetController()->GetCmd(), 2); if (block > GetBlockCount()) { - LOGTRACE("%s", ("Capacity of " + to_string(GetBlockCount()) + " block(s) exceeded: Trying to access block " - + to_string(block)).c_str()) + GetLogger().Trace("Capacity of " + to_string(GetBlockCount()) + " block(s) exceeded: Trying to access block " + + to_string(block)); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE); } } @@ -651,13 +652,14 @@ tuple Disk::CheckAndGetStartAndCount(access_mode mode) } } - LOGTRACE("%s READ/WRITE/VERIFY/SEEK command record=$%08X blocks=%d", __PRETTY_FUNCTION__, - static_cast(start), count) + stringstream s; + s << "READ/WRITE/VERIFY/SEEK, start block: $" << setfill('0') << setw(8) << hex << start; + GetLogger().Trace(s.str() + ", blocks: " + to_string(count)); // Check capacity if (uint64_t capacity = GetBlockCount(); !capacity || start > capacity || start + count > capacity) { - LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block " - + to_string(start) + ", block count " + to_string(count)).c_str()) + GetLogger().Trace("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block " + + to_string(start) + ", block count " + to_string(count)); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE); } diff --git a/cpp/devices/disk_track.cpp b/cpp/devices/disk_track.cpp index 8f046be1..2b4f4008 100644 --- a/cpp/devices/disk_track.cpp +++ b/cpp/devices/disk_track.cpp @@ -75,7 +75,7 @@ bool DiskTrack::Load(const string& path) if (dt.buffer == nullptr) { if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { - LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__) + LOGWARN("posix_memalign failed") } dt.length = length; } @@ -88,7 +88,7 @@ bool DiskTrack::Load(const string& path) if (dt.length != static_cast(length)) { free(dt.buffer); if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { - LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__) + LOGWARN("posix_memalign failed") } dt.length = length; } @@ -219,8 +219,6 @@ bool DiskTrack::ReadSector(vector& buf, int sec) const { assert(sec >= 0 && sec < 0x100); - LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec) - // Error if not initialized if (!dt.init) { return false; diff --git a/cpp/devices/mode_page_device.cpp b/cpp/devices/mode_page_device.cpp index 2c6e5535..6803b149 100644 --- a/cpp/devices/mode_page_device.cpp +++ b/cpp/devices/mode_page_device.cpp @@ -9,11 +9,12 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "mode_page_device.h" #include +#include +#include using namespace std; using namespace scsi_defs; @@ -43,14 +44,17 @@ int ModePageDevice::AddModePages(const vector& cdb, vector& buf, i // Get page code (0x3f means all pages) const int page = cdb[2] & 0x3f; - LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page) + stringstream s; + s << "Requesting mode page $" << setfill('0') << setw(2) << hex << page; + GetLogger().Trace(s.str()); // Mode page data mapped to the respective page numbers, C++ maps are ordered by key map> pages; SetUpModePages(pages, page, changeable); if (pages.empty()) { - LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page) + s << "Unsupported mode page $" << page; + GetLogger().Trace(s.str()); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); } diff --git a/cpp/devices/primary_device.cpp b/cpp/devices/primary_device.cpp index 02a92924..e7d49595 100644 --- a/cpp/devices/primary_device.cpp +++ b/cpp/devices/primary_device.cpp @@ -7,10 +7,11 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "primary_device.h" +#include +#include using namespace std; using namespace scsi_defs; @@ -41,13 +42,17 @@ void PrimaryDevice::AddCommand(scsi_command opcode, const operation& execute) void PrimaryDevice::Dispatch(scsi_command cmd) { + stringstream s; + s << "$" << setfill('0') << setw(2) << hex << static_cast(cmd); + if (const auto& it = commands.find(cmd); it != commands.end()) { - LOGDEBUG("Executing %s ($%02X)", command_mapping.find(cmd)->second.second, static_cast(cmd)) + GetLogger().Debug("Device is executing " + string(command_mapping.find(cmd)->second.second) + + " (" + s.str() + ")"); it->second(); } else { - LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetId(), GetLun(), static_cast(cmd)) + GetLogger().Trace("Received unsupported command: " + s.str()); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE); } @@ -63,7 +68,7 @@ void PrimaryDevice::Reset() int PrimaryDevice::GetId() const { if (GetController() == nullptr) { - LOGERROR("Device is missing its controller") + GetLogger().Error("Device is missing its controller"); } return GetController() != nullptr ? GetController()->GetTargetId() : -1; @@ -72,6 +77,8 @@ int PrimaryDevice::GetId() const void PrimaryDevice::SetController(shared_ptr c) { controller = c; + + logger.SetIdAndLun(c != nullptr ? c->GetTargetId() : -1, GetLun()); } void PrimaryDevice::TestUnitReady() @@ -97,7 +104,7 @@ void PrimaryDevice::Inquiry() // Report if the device does not support the requested LUN if (int lun = GetController()->GetEffectiveLun(); !GetController()->HasDeviceForLun(lun)) { - LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, GetId()) + GetLogger().Trace("LUN is not available"); // Signal that the requested LUN does not exist GetController()->GetBuffer().data()[0] = 0x7f; @@ -183,25 +190,24 @@ void PrimaryDevice::CheckReady() // Not ready if reset if (IsReset()) { SetReset(false); - LOGTRACE("%s Device in reset", __PRETTY_FUNCTION__) + GetLogger().Trace("Device in reset"); throw scsi_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET); } // Not ready if it needs attention if (IsAttn()) { SetAttn(false); - LOGTRACE("%s Device in needs attention", __PRETTY_FUNCTION__) + GetLogger().Trace("Device in needs attention"); throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE); } // Return status if not ready if (!IsReady()) { - LOGTRACE("%s Device not ready", __PRETTY_FUNCTION__) + GetLogger().Trace("Device not ready"); throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT); } - // Initialization with no error - LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__) + GetLogger().Trace("Device is ready"); } vector PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const @@ -246,15 +252,19 @@ vector PrimaryDevice::HandleRequestSense() const buf[12] = (byte)(GetStatusCode() >> 8); buf[13] = (byte)GetStatusCode(); - LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, static_cast(GetController()->GetStatus()), - static_cast(buf[2]), static_cast(buf[12])) + stringstream s; + s << setfill('0') << setw(2) << hex + << "Status $" << static_cast(GetController()->GetStatus()) + << ", Sense Key $" << static_cast(buf[2]) + << ", ASC $" << static_cast(buf[12]); + GetLogger().Trace(s.str()); return buf; } bool PrimaryDevice::WriteByteSequence(vector&, uint32_t) { - LOGERROR("%s Writing bytes is not supported by this device", __PRETTY_FUNCTION__) + GetLogger().Error("Writing bytes is not supported by this device"); return false; } @@ -264,10 +274,10 @@ void PrimaryDevice::ReserveUnit() reserving_initiator = GetController()->GetInitiatorId(); if (reserving_initiator != -1) { - LOGTRACE("Reserved device ID %d, LUN %d for initiator ID %d", GetId(), GetLun(), reserving_initiator) + GetLogger().Trace("Reserved device for initiator ID " + to_string(reserving_initiator)); } else { - LOGTRACE("Reserved device ID %d, LUN %d for unknown initiator", GetId(), GetLun()) + GetLogger().Trace("Reserved device for unknown initiator"); } EnterStatusPhase(); @@ -276,10 +286,10 @@ void PrimaryDevice::ReserveUnit() void PrimaryDevice::ReleaseUnit() { if (reserving_initiator != -1) { - LOGTRACE("Released device ID %d, LUN %d reserved by initiator ID %d", GetId(), GetLun(), reserving_initiator) + GetLogger().Trace("Released device reserved by initiator ID " + to_string(reserving_initiator)); } else { - LOGTRACE("Released device ID %d, LUN %d reserved by unknown initiator", GetId(), GetLun()) + GetLogger().Trace("Released device reserved by unknown initiator"); } DiscardReservation(); @@ -303,10 +313,10 @@ bool PrimaryDevice::CheckReservation(int initiator_id, scsi_command cmd, bool pr } if (initiator_id != -1) { - LOGTRACE("Initiator ID %d tries to access reserved device ID %d, LUN %d", initiator_id, GetId(), GetLun()) + GetLogger().Trace("Initiator ID " + to_string(initiator_id) + " tries to access reserved device"); } else { - LOGTRACE("Unknown initiator tries to access reserved device ID %d, LUN %d", GetId(), GetLun()) + GetLogger().Trace("Unknown initiator tries to access reserved device"); } return false; diff --git a/cpp/devices/primary_device.h b/cpp/devices/primary_device.h index 254433d8..ade76347 100644 --- a/cpp/devices/primary_device.h +++ b/cpp/devices/primary_device.h @@ -15,6 +15,7 @@ #include "interfaces/scsi_primary_commands.h" #include "controllers/abstract_controller.h" #include "device.h" +#include "device_logger.h" #include #include #include @@ -56,6 +57,8 @@ protected: void AddCommand(scsi_command, const operation&); + const DeviceLogger& GetLogger() const { return logger; } + vector HandleInquiry(scsi_defs::device_type, scsi_level, bool) const; virtual vector InquiryInternal() const = 0; void CheckReady(); @@ -83,6 +86,8 @@ private: vector HandleRequestSense() const; + DeviceLogger logger; + weak_ptr controller; unordered_map commands; diff --git a/cpp/devices/scsi_command_util.cpp b/cpp/devices/scsi_command_util.cpp index b4b6e426..c8f1e48f 100644 --- a/cpp/devices/scsi_command_util.cpp +++ b/cpp/devices/scsi_command_util.cpp @@ -7,14 +7,18 @@ // //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" +#include "device_logger.h" #include "scsi_command_util.h" +#include +#include +#include +#include using namespace scsi_defs; -void scsi_command_util::ModeSelect(scsi_command cmd, const vector& cdb, const vector& buf, int length, - int sector_size) +void scsi_command_util::ModeSelect(const DeviceLogger& logger, scsi_command cmd, const vector& cdb, + const vector& buf, int length, int sector_size) { assert(cmd == scsi_command::eCmdModeSelect6 || cmd == scsi_command::eCmdModeSelect10); assert(length >= 0); @@ -52,14 +56,16 @@ void scsi_command_util::ModeSelect(scsi_command cmd, const vector& cdb, con if (GetInt16(buf, offset + 12) != 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") + logger.Warn("In order to change the sector size use the -b option when launching rascsi"); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST); } has_valid_page_code = true; } else { - LOGWARN("Unknown MODE SELECT page code: $%02X", page) + stringstream s; + s << "Unknown MODE SELECT page code: $" << setfill('0') << setw(2) << hex << page; + logger.Warn(s.str()); } // Advance to the next page diff --git a/cpp/devices/scsi_command_util.h b/cpp/devices/scsi_command_util.h index 209c3df2..3aef09ae 100644 --- a/cpp/devices/scsi_command_util.h +++ b/cpp/devices/scsi_command_util.h @@ -17,9 +17,11 @@ using namespace std; +class DeviceLogger; + namespace scsi_command_util { - void ModeSelect(scsi_defs::scsi_command, const vector&, const vector&, int, int); + void ModeSelect(const DeviceLogger&, scsi_defs::scsi_command, const vector&, const vector&, int, int); void EnrichFormatPage(map>&, bool, int); void AddAppleVendorModePage(map>&, bool); diff --git a/cpp/devices/scsi_daynaport.cpp b/cpp/devices/scsi_daynaport.cpp index beacae69..7374f9c2 100644 --- a/cpp/devices/scsi_daynaport.cpp +++ b/cpp/devices/scsi_daynaport.cpp @@ -24,14 +24,20 @@ // Note: This requires a DaynaPort SCSI Link driver. //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "scsi_daynaport.h" +#include +#include using namespace scsi_defs; using namespace scsi_command_util; +SCSIDaynaPort::SCSIDaynaPort(int lun) : PrimaryDevice(SCDP, lun) +{ + SupportsParams(true); +} + bool SCSIDaynaPort::Init(const unordered_map& params) { PrimaryDevice::Init(params); @@ -48,18 +54,16 @@ bool SCSIDaynaPort::Init(const unordered_map& params) // In the MacOS driver, it looks like the driver is doing two "READ" system calls. SetSendDelay(DAYNAPORT_READ_HEADER_SZ); - SupportsParams(true); - m_bTapEnable = m_tap.Init(GetParams()); if(!m_bTapEnable){ - LOGERROR("Unable to open the TAP interface") + GetLogger().Error("Unable to open the TAP interface"); // Not terminating on regular Linux PCs is helpful for testing #if !defined(__x86_64__) && !defined(__X86__) return false; #endif } else { - LOGDEBUG("Tap interface created") + GetLogger().Trace("Tap interface created"); } Reset(); @@ -118,7 +122,8 @@ int SCSIDaynaPort::Read(const vector& cdb, vector& buf, uint64_t) const auto response = (scsi_resp_read_t*)buf.data(); const int requested_length = cdb[4]; - LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length) + + GetLogger().Trace("Read maximum length: " + to_string(requested_length)); // At startup the host may send a READ(6) command with a sector count of 1 to read the root sector. // We should respond by going into the status mode with a code of 0x02. @@ -141,13 +146,13 @@ int SCSIDaynaPort::Read(const vector& cdb, vector& buf, uint64_t) // If we didn't receive anything, return size of 0 if (rx_packet_size <= 0) { - LOGTRACE("%s No packet received", __PRETTY_FUNCTION__) + GetLogger().Trace("No packet received"); response->length = 0; response->flags = read_data_flags_t::e_no_more_data; return DAYNAPORT_READ_HEADER_SZ; } - LOGTRACE("%s Packet Sz %d (%08X) read: %d", __PRETTY_FUNCTION__, (unsigned int) rx_packet_size, (unsigned int) rx_packet_size, read_count) + GetLogger().Trace("Packet Size " + to_string(rx_packet_size) + ", read count: " + to_string(read_count)); // This is a very basic filter to prevent unnecessary packets from // being sent to the SCSI initiator. @@ -177,14 +182,12 @@ int SCSIDaynaPort::Read(const vector& cdb, vector& buf, uint64_t) // configuration from SCSI command 0x0D if (!send_message_to_host) { - LOGDEBUG("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", \ - __PRETTY_FUNCTION__, - static_cast(response->data[0]), - static_cast(response->data[1]), - static_cast(response->data[2]), - static_cast(response->data[3]), - static_cast(response->data[4]), - static_cast(response->data[5])) + stringstream s; + s << "Received a packet that's not for me:" << setfill('0') << setw(2) << hex; + for (int i = 0 ; i < 6; i++) { + s << " $" << static_cast(response->data[i]); + } + GetLogger().Debug(s.str()); // If there are pending packets to be processed, we'll tell the host that the read // length was 0. @@ -253,16 +256,18 @@ bool SCSIDaynaPort::WriteBytes(const vector& cdb, vector& buf, uin if (data_format == 0x00) { m_tap.Send(buf.data(), data_length); - LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length) + GetLogger().Trace("Transmitted " + to_string(data_length) + " byte(s) (00 format)"); } else if (data_format == 0x80) { // The data length is specified in the first 2 bytes of the payload data_length = buf[1] + ((static_cast(buf[0]) & 0xff) << 8); m_tap.Send(&(buf.data()[4]), data_length); - LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length) + GetLogger().Trace("Transmitted " + to_string(data_length) + "byte(s) (80 format)"); } else { - LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format) + stringstream s; + s << "Unknown data format: " << setfill('0') << setw(2) << hex << data_format; + GetLogger().Warn(s.str()); } GetController()->SetBlocks(0); @@ -308,15 +313,16 @@ void SCSIDaynaPort::Read6() // If any commands have a bogus control value, they were probably not // generated by the DaynaPort driver so ignore them if (GetController()->GetCmd(5) != 0xc0 && GetController()->GetCmd(5) != 0x80) { - LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, - GetController()->GetCmd(5), GetController()->GetCmd(5)) + GetLogger().Trace("Control value: " + to_string(GetController()->GetCmd(5))); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); } - LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, GetController()->GetBlocks()) + stringstream s; + s << "READ(6) command, record: $" << setfill('0') << setw(8) << hex << record; + GetLogger().Trace(s.str() + ", blocks: " + to_string(GetController()->GetBlocks())); GetController()->SetLength(Read(GetController()->GetCmd(), GetController()->GetBuffer(), record)); - LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, GetController()->GetLength()) + GetLogger().Trace("Length is " + to_string(GetController()->GetLength())); // Set next block GetController()->SetNext(record + 1); @@ -338,10 +344,14 @@ void SCSIDaynaPort::Write6() const GetController()->SetLength(GetInt16(GetController()->GetCmd(), 3) + 8); } else { - LOGWARN("%s Unknown data format $%02X", __PRETTY_FUNCTION__, data_format) + stringstream s; + s << "Unknown data format: " << setfill('0') << setw(2) << hex << data_format; + GetLogger().Warn(s.str()); } - LOGTRACE("%s length: $%04X (%d) format: $%02X", __PRETTY_FUNCTION__, GetController()->GetLength(), - GetController()->GetLength(), data_format) + + stringstream s; + s << "Length: " << GetController()->GetLength() << ", format: $" << setfill('0') << setw(2) << hex << data_format; + GetLogger().Trace(s.str()); if (GetController()->GetLength() <= 0) { throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); @@ -398,7 +408,7 @@ void SCSIDaynaPort::SetInterfaceMode() const GetController()->SetLength(RetrieveStats(GetController()->GetCmd(), GetController()->GetBuffer())); switch(GetController()->GetCmd(5)){ case CMD_SCSILINK_SETMODE: - // TODO Not implemented, do nothing + // Not implemented, do nothing EnterStatusPhase(); break; @@ -407,15 +417,10 @@ void SCSIDaynaPort::SetInterfaceMode() const EnterDataOutPhase(); break; - case CMD_SCSILINK_STATS: - case CMD_SCSILINK_ENABLE: - case CMD_SCSILINK_SET: - LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, GetController()->GetCmd(5)) - throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE); - break; - default: - LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, GetController()->GetCmd(5)) + stringstream s; + s << "Unsupported SetInterface command: " << setfill('0') << setw(2) << hex << GetController()->GetCmd(5); + GetLogger().Warn(s.str()); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE); break; } @@ -425,8 +430,9 @@ void SCSIDaynaPort::SetMcastAddr() const { GetController()->SetLength(GetController()->GetCmd(4)); if (GetController()->GetLength() == 0) { - LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, GetController()->GetCmd(2)) - + stringstream s; + s << "Unsupported SetMcastAddr command: " << setfill('0') << setw(2) << hex << GetController()->GetCmd(2); + GetLogger().Warn(s.str()); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); } @@ -449,23 +455,23 @@ void SCSIDaynaPort::EnableInterface() { if (GetController()->GetCmd(5) & 0x80) { if (!m_tap.Enable()) { - LOGWARN("Unable to enable the DaynaPort Interface") + GetLogger().Warn("Unable to enable the DaynaPort Interface"); throw scsi_exception(sense_key::ABORTED_COMMAND); } m_tap.Flush(); - LOGINFO("The DaynaPort interface has been ENABLED") + GetLogger().Info("The DaynaPort interface has been ENABLED"); } else { if (!m_tap.Disable()) { - LOGWARN("Unable to disable the DaynaPort Interface") + GetLogger().Warn("Unable to disable the DaynaPort Interface"); throw scsi_exception(sense_key::ABORTED_COMMAND); } - LOGINFO("The DaynaPort interface has been DISABLED") + GetLogger().Info("The DaynaPort interface has been DISABLED"); } EnterStatusPhase(); diff --git a/cpp/devices/scsi_daynaport.h b/cpp/devices/scsi_daynaport.h index f5c66b8a..64630133 100644 --- a/cpp/devices/scsi_daynaport.h +++ b/cpp/devices/scsi_daynaport.h @@ -45,7 +45,7 @@ class SCSIDaynaPort : public PrimaryDevice, public ByteWriter { public: - explicit SCSIDaynaPort(int lun) : PrimaryDevice(SCDP, lun) {} + explicit SCSIDaynaPort(int); ~SCSIDaynaPort() override = default; bool Init(const unordered_map&) override; diff --git a/cpp/devices/scsi_host_bridge.cpp b/cpp/devices/scsi_host_bridge.cpp index f0e1bc70..beb921cd 100644 --- a/cpp/devices/scsi_host_bridge.cpp +++ b/cpp/devices/scsi_host_bridge.cpp @@ -16,7 +16,6 @@ // work with the Sharp X68000 operating system. //--------------------------------------------------------------------------- -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "scsi_host_bridge.h" @@ -27,6 +26,11 @@ using namespace std; using namespace scsi_defs; using namespace scsi_command_util; +SCSIBR::SCSIBR(int lun) : PrimaryDevice(SCBR, lun) +{ + SupportsParams(true); +} + bool SCSIBR::Init(const unordered_map& params) { PrimaryDevice::Init(params); @@ -38,13 +42,11 @@ bool SCSIBR::Init(const unordered_map& params) AddCommand(scsi_command::eCmdGetMessage10, [this] { GetMessage10(); }); AddCommand(scsi_command::eCmdSendMessage10, [this] { SendMessage10(); }); - SupportsParams(true); - #ifdef __linux__ // TAP Driver Generation m_bTapEnable = tap.Init(GetParams()); if (!m_bTapEnable){ - LOGERROR("Unable to open the TAP interface") + GetLogger().Error("Unable to open the TAP interface"); return false; } #endif diff --git a/cpp/devices/scsi_host_bridge.h b/cpp/devices/scsi_host_bridge.h index 6472a35c..92a8b24a 100644 --- a/cpp/devices/scsi_host_bridge.h +++ b/cpp/devices/scsi_host_bridge.h @@ -32,7 +32,7 @@ class SCSIBR : public PrimaryDevice, public ByteWriter public: - explicit SCSIBR(int lun) : PrimaryDevice(SCBR, lun) {} + explicit SCSIBR(int); ~SCSIBR() override = default; bool Init(const unordered_map&) override; diff --git a/cpp/devices/scsi_printer.cpp b/cpp/devices/scsi_printer.cpp index 0d4c7736..29b21587 100644 --- a/cpp/devices/scsi_printer.cpp +++ b/cpp/devices/scsi_printer.cpp @@ -29,7 +29,6 @@ // With STOP PRINT printing can be cancelled before SYNCHRONIZE BUFFER was sent. // -#include "shared/log.h" #include "shared/rascsi_exceptions.h" #include "scsi_command_util.h" #include "scsi_printer.h" @@ -41,6 +40,11 @@ using namespace filesystem; using namespace scsi_defs; using namespace scsi_command_util; +SCSIPrinter::SCSIPrinter(int lun) : PrimaryDevice(SCLP, lun) +{ + SupportsParams(true); +} + bool SCSIPrinter::Init(const unordered_map& params) { PrimaryDevice::Init(params); @@ -57,7 +61,7 @@ bool SCSIPrinter::Init(const unordered_map& params) AddCommand(scsi_command::eCmdSendDiagnostic, [this] { SendDiagnostic(); }); if (GetParam("cmd").find("%f") == string::npos) { - LOGERROR("Missing filename specifier %%f") + GetLogger().Trace("Missing filename specifier %f"); return false; } @@ -65,7 +69,6 @@ bool SCSIPrinter::Init(const unordered_map& params) file_template = temp_directory_path(error); //NOSONAR Publicly writable directory is fine here file_template += PRINTER_FILE_PATTERN; - SupportsParams(true); SetReady(true); return true; @@ -86,11 +89,11 @@ void SCSIPrinter::Print() { const uint32_t length = GetInt24(GetController()->GetCmd(), 2); - LOGTRACE("Receiving %d byte(s) to be printed", length) + GetLogger().Trace("Receiving " + to_string(length) + " byte(s) to be printed"); if (length > GetController()->GetBuffer().size()) { - LOGERROR("%s", ("Transfer buffer overflow: Buffer size is " + to_string(GetController()->GetBuffer().size()) + - " bytes, " + to_string(length) + " bytes expected").c_str()) + GetLogger().Error("Transfer buffer overflow: Buffer size is " + to_string(GetController()->GetBuffer().size()) + + " bytes, " + to_string(length) + " bytes expected"); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); } @@ -104,7 +107,7 @@ void SCSIPrinter::Print() void SCSIPrinter::SynchronizeBuffer() { if (!out.is_open()) { - LOGWARN("Nothing to print") + GetLogger().Warn("Nothing to print"); throw scsi_exception(sense_key::ABORTED_COMMAND); } @@ -116,12 +119,12 @@ void SCSIPrinter::SynchronizeBuffer() error_code error; - LOGTRACE("Printing file '%s' with %s byte(s)", filename.c_str(), to_string(file_size(path(filename), error)).c_str()) + GetLogger().Trace("Printing file '" + filename + "' with " + to_string(file_size(path(filename), error)) + " byte(s)"); - LOGDEBUG("Executing '%s'", cmd.c_str()) + GetLogger().Debug("Executing '" + cmd + "'"); if (system(cmd.c_str())) { - LOGERROR("Printing file '%s' failed, the printing system might not be configured", filename.c_str()) + GetLogger().Error("Printing file '" + filename + "' failed, the printing system might not be configured"); Cleanup(); @@ -142,7 +145,7 @@ bool SCSIPrinter::WriteByteSequence(vector& buf, uint32_t length) // There is no C++ API that generates a file with a unique name const int fd = mkstemp(f.data()); if (fd == -1) { - LOGERROR("Can't create printer output file for pattern '%s': %s", filename.c_str(), strerror(errno)) + GetLogger().Error("Can't create printer output file for pattern '" + filename + "': " + strerror(errno)); return false; } close(fd); @@ -154,10 +157,10 @@ bool SCSIPrinter::WriteByteSequence(vector& buf, uint32_t length) throw scsi_exception(sense_key::ABORTED_COMMAND); } - LOGTRACE("Created printer output file '%s'", filename.c_str()) + GetLogger().Trace("Created printer output file '" + filename + "'"); } - LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename.c_str()) + GetLogger().Trace("Appending " + to_string(length) + " byte(s) to printer output file ''" + filename + "'"); out.write((const char*)buf.data(), length); diff --git a/cpp/devices/scsi_printer.h b/cpp/devices/scsi_printer.h index ca9995e7..43a6c62b 100644 --- a/cpp/devices/scsi_printer.h +++ b/cpp/devices/scsi_printer.h @@ -26,7 +26,7 @@ class SCSIPrinter : public PrimaryDevice, private ScsiPrinterCommands public: - explicit SCSIPrinter(int lun) : PrimaryDevice(SCLP, lun) {} + explicit SCSIPrinter(int); ~SCSIPrinter() override = default; bool Init(const unordered_map&) override; diff --git a/cpp/devices/scsicd.cpp b/cpp/devices/scsicd.cpp index 12fa2998..3cd74178 100644 --- a/cpp/devices/scsicd.cpp +++ b/cpp/devices/scsicd.cpp @@ -26,6 +26,10 @@ using namespace scsi_command_util; SCSICD::SCSICD(int lun, const unordered_set& sector_sizes) : Disk(SCCD, lun) { SetSectorSizes(sector_sizes); + + SetReadOnly(true); + SetRemovable(true); + SetLockable(true); } bool SCSICD::Init(const unordered_map& params) @@ -34,10 +38,6 @@ bool SCSICD::Init(const unordered_map& params) AddCommand(scsi_command::eCmdReadToc, [this] { ReadToc(); }); - SetReadOnly(true); - SetRemovable(true); - SetLockable(true); - return true; } diff --git a/cpp/devices/scsihd.cpp b/cpp/devices/scsihd.cpp index f3a2efe2..6ad819a7 100644 --- a/cpp/devices/scsihd.cpp +++ b/cpp/devices/scsihd.cpp @@ -86,7 +86,7 @@ vector SCSIHD::InquiryInternal() const void SCSIHD::ModeSelect(scsi_command cmd, const vector& cdb, const vector& buf, int length) const { - scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); + scsi_command_util::ModeSelect(GetLogger(), cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); } void SCSIHD::AddFormatPage(map>& pages, bool changeable) const diff --git a/cpp/devices/scsimo.cpp b/cpp/devices/scsimo.cpp index 967c076d..3329bea1 100644 --- a/cpp/devices/scsimo.cpp +++ b/cpp/devices/scsimo.cpp @@ -91,7 +91,7 @@ void SCSIMO::AddOptionPage(map>& pages, bool) const void SCSIMO::ModeSelect(scsi_command cmd, const vector& cdb, const vector& buf, int length) const { - scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); + scsi_command_util::ModeSelect(GetLogger(), cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); } // diff --git a/cpp/monitor/sm_core.cpp b/cpp/monitor/sm_core.cpp index 046063a5..aeebd67e 100644 --- a/cpp/monitor/sm_core.cpp +++ b/cpp/monitor/sm_core.cpp @@ -26,9 +26,6 @@ using namespace std; using namespace ras_util; -// TODO Should not be global and not be used by sm_vcd_report -double ns_per_loop; - void ScsiMon::KillHandler(int) { running = false; @@ -75,19 +72,6 @@ void ScsiMon::ParseArguments(const vector& args) html_file_name += ".html"; } -void ScsiMon::PrintCopyrightText() const -{ - LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ") - LOGINFO("version %s (%s, %s)", - rascsi_get_version_string().c_str(), - __DATE__, - __TIME__) - LOGINFO("Powered by XM6 TypeG Technology ") - LOGINFO("Copyright (C) 2016-2020 GIMONS") - LOGINFO("Copyright (C) 2020-2022 Contributors to the RaSCSI project") - LOGINFO(" ") -} - void ScsiMon::PrintHelpText(const vector& args) const { LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0]) @@ -174,7 +158,8 @@ int ScsiMon::run(const vector& args) #endif spdlog::set_pattern("%^[%l]%$ %v"); - PrintCopyrightText(); + ras_util::Banner("SCSI Monitor Capture Tool"); + ParseArguments(args); #ifdef DEBUG diff --git a/cpp/monitor/sm_core.h b/cpp/monitor/sm_core.h index 4d66353a..a7cfdb9e 100644 --- a/cpp/monitor/sm_core.h +++ b/cpp/monitor/sm_core.h @@ -26,10 +26,11 @@ public: int run(const vector&); + inline static double ns_per_loop; + private: void ParseArguments(const vector&); - void PrintCopyrightText() const; void PrintHelpText(const vector&) const; void Banner() const; bool Init(); @@ -57,5 +58,4 @@ private: string json_file_name; string html_file_name; string input_file_name; - }; diff --git a/cpp/monitor/sm_vcd_report.cpp b/cpp/monitor/sm_vcd_report.cpp index 95bb7be6..a0d747fd 100644 --- a/cpp/monitor/sm_vcd_report.cpp +++ b/cpp/monitor/sm_vcd_report.cpp @@ -12,6 +12,7 @@ #include "shared/log.h" #include "hal/gpiobus.h" #include "data_sample.h" +#include "sm_core.h" #include "sm_reports.h" #include #include @@ -50,8 +51,6 @@ const int PIN_PHASE = 0; //--------------------------------------------------------------------------- static uint8_t prev_value[32] = {0xFF}; -extern double ns_per_loop; - static uint8_t get_pin_value(uint32_t data, int pin) { return (data >> pin) & 1; @@ -164,7 +163,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture uint32_t i = 0; while (i < capture_count) { - vcd_ofstream << "#" << (uint64_t)((double)data_capture_array[i].timestamp * ns_per_loop) << endl; + vcd_ofstream << "#" << (uint64_t)((double)data_capture_array[i].timestamp * ScsiMon::ns_per_loop) << endl; vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD); diff --git a/cpp/rascsi/rascsi_core.cpp b/cpp/rascsi/rascsi_core.cpp index d368840e..80c24e48 100644 --- a/cpp/rascsi/rascsi_core.cpp +++ b/cpp/rascsi/rascsi_core.cpp @@ -133,6 +133,18 @@ void Rascsi::LogDevices(string_view devices) const } } +PbDeviceType Rascsi::ParseDeviceType(const string& value) const +{ + string t = value; + PbDeviceType type; + transform(t.begin(), t.end(), t.begin(), ::toupper); + if (!PbDeviceType_Parse(t, &type)) { + throw parser_exception("Illegal device type '" + value + "'"); + } + + return type; +} + void Rascsi::TerminationHandler(int signum) { Cleanup(); @@ -216,12 +228,11 @@ Rascsi::optargs_type Rascsi::ParseArguments(const vector& args, int& por void Rascsi::CreateInitialDevices(const optargs_type& optargs) const { PbCommand command; - int id = -1; - int lun = -1; PbDeviceType type = UNDEFINED; int block_size = 0; string name; string log_level; + string id_and_lun; const char *locale = setlocale(LC_MESSAGES, ""); if (locale == nullptr || !strcmp(locale, "C")) { @@ -233,15 +244,12 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const switch (option) { case 'i': case 'I': - id = -1; - lun = -1; continue; case 'd': - case 'D': { - ProcessId(value, ScsiController::LUN_MAX, id, lun); + case 'D': + id_and_lun = value; continue; - } case 'z': locale = value.c_str(); @@ -271,13 +279,8 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const } continue; - case 't': { - string t = value; - transform(t.begin(), t.end(), t.begin(), ::toupper); - if (!PbDeviceType_Parse(t, &type)) { - throw parser_exception("Illegal device type '" + value + "'"); - } - } + case 't': + type = ParseDeviceType(value); continue; case 1: @@ -288,35 +291,25 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const throw parser_exception("Parser error"); } - // Set up the device data PbDeviceDefinition *device = command.add_devices(); - device->set_id(id); - device->set_unit(lun); + + if (!id_and_lun.empty()) { + if (const string error = SetIdAndLun(*device, id_and_lun, ScsiController::LUN_MAX); !error.empty()) { + throw parser_exception(error); + } + } + device->set_type(type); device->set_block_size(block_size); ParseParameters(*device, value); - if (size_t separator_pos = name.find(COMPONENT_SEPARATOR); separator_pos != string::npos) { - device->set_vendor(name.substr(0, separator_pos)); - name = name.substr(separator_pos + 1); - separator_pos = name.find(COMPONENT_SEPARATOR); - if (separator_pos != string::npos) { - device->set_product(name.substr(0, separator_pos)); - device->set_revision(name.substr(separator_pos + 1)); - } - else { - device->set_product(name); - } - } - else { - device->set_vendor(name); - } + SetProductData(*device, name); - id = -1; type = UNDEFINED; block_size = 0; name = ""; + id_and_lun = ""; } // Attach all specified devices @@ -485,7 +478,7 @@ bool Rascsi::ExecuteCommand(const CommandContext& context, const PbCommand& comm return true; } -int Rascsi::run(const vector& args) const +int Rascsi::run(const vector& args) { GOOGLE_PROTOBUF_VERIFY_VERSION; @@ -579,22 +572,14 @@ int Rascsi::run(const vector& args) const // 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()) { - const uint32_t now = SysTimer::GetTimerLow(); - while ((SysTimer::GetTimerLow() - now) < 3'000'000) { - bus->Acquire(); - if (!bus->GetBSY()) { - break; - } - } - } + WaitForNotBusy(); // Stop because the bus is busy or another device responded if (bus->GetBSY() || !bus->GetSEL()) { continue; } - int initiator_id = -1; + int initiator_id = AbstractController::UNKNOWN_INITIATOR_ID; // The initiator and target ID const uint8_t id_data = bus->GetDAT(); @@ -604,8 +589,17 @@ int Rascsi::run(const vector& args) const // Identify the responsible controller auto controller = controller_manager->IdentifyController(id_data); if (controller != nullptr) { + device_logger.SetIdAndLun(controller->GetTargetId(), -1); + initiator_id = controller->ExtractInitiatorId(id_data); + if (initiator_id != AbstractController::UNKNOWN_INITIATOR_ID) { + device_logger.Trace("++++ Starting processing for initiator ID " + to_string(initiator_id)); + } + else { + device_logger.Trace("++++ Starting processing for unknown initiator ID"); + } + if (controller->Process(initiator_id) == BUS::phase_t::selection) { phase = BUS::phase_t::selection; } @@ -648,3 +642,19 @@ int Rascsi::run(const vector& args) const return EXIT_SUCCESS; } + +void Rascsi::WaitForNotBusy() const +{ + if (bus->GetBSY()) { + const uint32_t now = SysTimer::GetTimerLow(); + + // Wait for 3s + while ((SysTimer::GetTimerLow() - now) < 3'000'000) { + bus->Acquire(); + + if (!bus->GetBSY()) { + break; + } + } + } +} diff --git a/cpp/rascsi/rascsi_core.h b/cpp/rascsi/rascsi_core.h index 818a6f9c..fd62067a 100644 --- a/cpp/rascsi/rascsi_core.h +++ b/cpp/rascsi/rascsi_core.h @@ -9,6 +9,7 @@ #pragma once +#include "devices/device_logger.h" #include "rascsi/command_context.h" #include "rascsi/rascsi_service.h" #include "rascsi/rascsi_image.h" @@ -34,7 +35,7 @@ public: Rascsi() = default; ~Rascsi() = default; - int run(const vector&) const; + int run(const vector&); private: @@ -43,13 +44,17 @@ private: static void Cleanup(); void ReadAccessToken(const string&) const; void LogDevices(string_view) const; + PbDeviceType ParseDeviceType(const string&) const; static void TerminationHandler(int); optargs_type ParseArguments(const vector&, int&) const; void CreateInitialDevices(const optargs_type&) const; + void WaitForNotBusy() const; // TODO Should not be static and should be moved to RascsiService static bool ExecuteCommand(const CommandContext&, const PbCommand&); + DeviceLogger device_logger; + // A static instance is needed because of the signal handler static inline shared_ptr bus; diff --git a/cpp/rascsi/rascsi_executor.cpp b/cpp/rascsi/rascsi_executor.cpp index 7f5edc33..51923c84 100644 --- a/cpp/rascsi/rascsi_executor.cpp +++ b/cpp/rascsi/rascsi_executor.cpp @@ -13,6 +13,7 @@ #include "shared/rascsi_exceptions.h" #include "controllers/controller_manager.h" #include "controllers/scsi_controller.h" +#include "devices/device_logger.h" #include "devices/device_factory.h" #include "devices/primary_device.h" #include "devices/disk.h" @@ -167,31 +168,49 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand& bool RascsiExecutor::SetLogLevel(const string& log_level) const { - if (log_level == "trace") { - set_level(level::trace); + int id = -1; + int lun = -1; + string level = log_level; + + if (size_t separator_pos = log_level.find(COMPONENT_SEPARATOR); separator_pos != string::npos) { + level = log_level.substr(0, separator_pos); + + const string l = log_level.substr(separator_pos + 1); + separator_pos = l.find(COMPONENT_SEPARATOR); + if (separator_pos != string::npos) { + const string error = ProcessId(l, ScsiController::LUN_MAX, id, lun); + if (!error.empty()) { + LOGWARN("Invalid device ID/LUN specifier '%s'", l.c_str()) + return false; + } + } + else if (!GetAsUnsignedInt(l, id)) { + LOGWARN("Invalid device ID specifier '%s'", l.c_str()) + return false; + } } - else if (log_level == "debug") { - set_level(level::debug); - } - else if (log_level == "info") { - set_level(level::info); - } - else if (log_level == "warn") { - set_level(level::warn); - } - else if (log_level == "err") { - set_level(level::err); - } - else if (log_level == "off") { - set_level(level::off); + + if (const auto& it = log_level_mapping.find(level); it != log_level_mapping.end()) { + set_level(it->second); } else { LOGWARN("Invalid log level '%s'", log_level.c_str()) - return false; } - LOGINFO("Set log level to '%s'", log_level.c_str()) + DeviceLogger::SetLogIdAndLun(id, lun); + + if (id != -1) { + if (lun == -1) { + LOGINFO("Set log level for device ID %d to '%s'", id, level.c_str()) + } + else { + LOGINFO("Set log level for device ID %d, LUN %d to '%s'", id, lun, level.c_str()) + } + } + else { + LOGINFO("Set log level to '%s'", level.c_str()) + } return true; } diff --git a/cpp/rascsi/rascsi_executor.h b/cpp/rascsi/rascsi_executor.h index e3c75907..1171ebe8 100644 --- a/cpp/rascsi/rascsi_executor.h +++ b/cpp/rascsi/rascsi_executor.h @@ -9,8 +9,11 @@ #pragma once +#include "spdlog/spdlog.h" #include "shared/protobuf_serializer.h" #include "rascsi/rascsi_response.h" +#include +#include class RascsiImage; class DeviceFactory; @@ -18,6 +21,8 @@ class ControllerManager; class PrimaryDevice; class CommandContext; +using namespace spdlog; + class RascsiExecutor { public: @@ -66,4 +71,13 @@ private: const ProtobufSerializer serializer; unordered_set reserved_ids; + + static inline const unordered_map log_level_mapping = { + { "trace", level::trace }, + { "debug", level::debug }, + { "info", level::info }, + { "warn", level::warn }, + { "err", level::err }, + { "off", level::off } + }; }; diff --git a/cpp/rasctl/rasctl_core.cpp b/cpp/rasctl/rasctl_core.cpp index ebf5dd9c..3617a774 100644 --- a/cpp/rasctl/rasctl_core.cpp +++ b/cpp/rasctl/rasctl_core.cpp @@ -5,8 +5,7 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS -// Copyright (C) 2020-2021 Contributors to the RaSCSI project -// [ Send Control Command ] +// Copyright (C) 2020-2022 Contributors to the RaSCSI project // //--------------------------------------------------------------------------- @@ -88,20 +87,12 @@ int RasCtl::run(const vector& args) const while ((opt = getopt(static_cast(args.size()), args.data(), "e::lmos::vDINOTVXa:b:c:d:f:h:i:n:p:r:t:x:z:C:E:F:L:P::R:")) != -1) { switch (opt) { - case 'i': { - int id; - int lun; - try { - ProcessId(optarg, ScsiController::LUN_MAX, id, lun); - } - catch(const parser_exception& e) { - cerr << "Error: " << e.what() << endl; + case 'i': + if (const string error = SetIdAndLun(*device, optarg, ScsiController::LUN_MAX); !error.empty()) { + cerr << "Error: " << error << endl; exit(EXIT_FAILURE); } - device->set_id(id); - device->set_unit(lun); break; - } case 'C': command.set_operation(CREATE_IMAGE); @@ -206,32 +197,8 @@ int RasCtl::run(const vector& args) const image_params = optarg; break; - case 'n': { - string vendor; - string product; - string revision; - - string s = optarg; - if (size_t separator_pos = s.find(COMPONENT_SEPARATOR); separator_pos != string::npos) { - vendor = s.substr(0, separator_pos); - s = s.substr(separator_pos + 1); - separator_pos = s.find(COMPONENT_SEPARATOR); - if (separator_pos != string::npos) { - product = s.substr(0, separator_pos); - revision = s.substr(separator_pos + 1); - } - else { - product = s; - } - } - else { - vendor = s; - } - - device->set_vendor(vendor); - device->set_product(product); - device->set_revision(revision); - } + case 'n': + SetProductData(*device, optarg); break; case 'p': diff --git a/cpp/rasctl/rasctl_core.h b/cpp/rasctl/rasctl_core.h index 70ccfed9..bd4f5c40 100644 --- a/cpp/rasctl/rasctl_core.h +++ b/cpp/rasctl/rasctl_core.h @@ -9,9 +9,12 @@ #pragma once +#include "generated/rascsi_interface.pb.h" #include +#include using namespace std; +using namespace rascsi_interface; class RasCtl { diff --git a/cpp/rasdump/rasdump_core.cpp b/cpp/rasdump/rasdump_core.cpp index a96f086c..fe9cd13c 100644 --- a/cpp/rasdump/rasdump_core.cpp +++ b/cpp/rasdump/rasdump_core.cpp @@ -107,8 +107,12 @@ void RasDump::ParseArguments(const vector& args) break; - case 't': - ProcessId(optarg, 8, target_id, target_lun); + case 't': { + const string error = ProcessId(optarg, 8, target_id, target_lun); + if (!error.empty()) { + throw parser_exception(error); + } + } break; case 'v': diff --git a/cpp/rasdump/rasdump_core.h b/cpp/rasdump/rasdump_core.h index b0eab3fd..79a2a0c6 100644 --- a/cpp/rasdump/rasdump_core.h +++ b/cpp/rasdump/rasdump_core.h @@ -14,7 +14,6 @@ #include #include #include -#include using namespace std; diff --git a/cpp/shared/log.h b/cpp/shared/log.h index 90ec26d2..9898c221 100644 --- a/cpp/shared/log.h +++ b/cpp/shared/log.h @@ -6,14 +6,12 @@ // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS // Copyright (C) 2020 akuker -// [ Logging utilities ] // //--------------------------------------------------------------------------- #pragma once #include "spdlog/spdlog.h" -#include "spdlog/sinks/sink.h" static const int LOGBUF_SIZE = 512; diff --git a/cpp/shared/protobuf_util.cpp b/cpp/shared/protobuf_util.cpp index e9513865..3ff6a8e0 100644 --- a/cpp/shared/protobuf_util.cpp +++ b/cpp/shared/protobuf_util.cpp @@ -96,6 +96,41 @@ void protobuf_util::SetPatternParams(PbCommand& command, string_view patterns) SetParam(command, "file_pattern", file_pattern); } +void protobuf_util::SetProductData(PbDeviceDefinition& device, const string& data) +{ + string name = data; + + if (size_t separator_pos = name.find(COMPONENT_SEPARATOR); separator_pos != string::npos) { + device.set_vendor(name.substr(0, separator_pos)); + name = name.substr(separator_pos + 1); + separator_pos = name.find(COMPONENT_SEPARATOR); + if (separator_pos != string::npos) { + device.set_product(name.substr(0, separator_pos)); + device.set_revision(name.substr(separator_pos + 1)); + } + else { + device.set_product(name); + } + } + else { + device.set_vendor(name); + } +} + +string protobuf_util::SetIdAndLun(PbDeviceDefinition& device, const string& value, int max_luns) +{ + int id; + int lun; + if (const string error = ProcessId(value, max_luns, id, lun); !error.empty()) { + return error; + } + + device.set_id(id); + device.set_unit(lun); + + return ""; +} + string protobuf_util::ListDevices(const list& pb_devices) { if (pb_devices.empty()) { diff --git a/cpp/shared/protobuf_util.h b/cpp/shared/protobuf_util.h index 9e8fb8eb..d3603006 100644 --- a/cpp/shared/protobuf_util.h +++ b/cpp/shared/protobuf_util.h @@ -30,5 +30,7 @@ namespace protobuf_util void SetParam(PbDevice&, const string&, string_view); void SetParam(PbDeviceDefinition&, const string&, string_view); void SetPatternParams(PbCommand&, string_view); + void SetProductData(PbDeviceDefinition&, const string&); + string SetIdAndLun(PbDeviceDefinition&, const string&, int); string ListDevices(const list&); } diff --git a/cpp/shared/rasutil.cpp b/cpp/shared/rasutil.cpp index 57e51e31..897175e3 100644 --- a/cpp/shared/rasutil.cpp +++ b/cpp/shared/rasutil.cpp @@ -7,9 +7,9 @@ // //--------------------------------------------------------------------------- -#include "rascsi_exceptions.h" #include "rascsi_version.h" #include "rasutil.h" +#include #include #include @@ -35,19 +35,35 @@ bool ras_util::GetAsUnsignedInt(const string& value, int& result) return true; } -void ras_util::ProcessId(const string& id_spec, int max_luns, int& id, int& lun) +string ras_util::ProcessId(const string& id_spec, int max_luns, int& id, int& lun) { + assert(max_luns > 0); + + id = -1; + lun = -1; + + if (id_spec.empty()) { + return "Missing device ID"; + } + if (const size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) { if (!GetAsUnsignedInt(id_spec, id) || id >= 8) { - throw parser_exception("Invalid device ID (0-7)"); + id = -1; + + return "Invalid device ID (0-7)"; } lun = 0; } else if (!GetAsUnsignedInt(id_spec.substr(0, separator_pos), id) || id > 7 || !GetAsUnsignedInt(id_spec.substr(separator_pos + 1), lun) || lun >= max_luns) { - throw parser_exception("Invalid LUN (0-" + to_string(max_luns - 1) + ")"); + id = -1; + lun = -1; + + return "Invalid LUN (0-" + to_string(max_luns - 1) + ")"; } + + return ""; } string ras_util::Banner(const string& app) diff --git a/cpp/shared/rasutil.h b/cpp/shared/rasutil.h index afb94258..2e733a16 100644 --- a/cpp/shared/rasutil.h +++ b/cpp/shared/rasutil.h @@ -19,7 +19,7 @@ namespace ras_util static const char COMPONENT_SEPARATOR = ':'; bool GetAsUnsignedInt(const string&, int&); - void ProcessId(const string&, int, int&, int&); + string ProcessId(const string&, int, int&, int&); string Banner(const string&); string GetExtensionLowerCase(const string&); diff --git a/cpp/test/abstract_controller_test.cpp b/cpp/test/abstract_controller_test.cpp index 302d197c..61245aff 100644 --- a/cpp/test/abstract_controller_test.cpp +++ b/cpp/test/abstract_controller_test.cpp @@ -199,14 +199,13 @@ TEST(AbstractControllerTest, ExtractInitiatorId) { const int ID = 1; const int INITIATOR_ID = 7; - const int UNKNOWN_INITIATOR_ID = -1; auto bus = make_shared(); auto controller_manager = make_shared(*bus); MockAbstractController controller(controller_manager, ID); EXPECT_EQ(INITIATOR_ID, controller.ExtractInitiatorId((1 << INITIATOR_ID) | ( 1 << ID))); - EXPECT_EQ(UNKNOWN_INITIATOR_ID, controller.ExtractInitiatorId(1 << ID)); + EXPECT_EQ(AbstractController::UNKNOWN_INITIATOR_ID, controller.ExtractInitiatorId(1 << ID)); } TEST(AbstractControllerTest, GetOpcode) diff --git a/cpp/test/device_factory_test.cpp b/cpp/test/device_factory_test.cpp index c3ef0492..103bdc19 100644 --- a/cpp/test/device_factory_test.cpp +++ b/cpp/test/device_factory_test.cpp @@ -140,9 +140,6 @@ TEST(DeviceFactoryTest, SCHD_Device_Defaults) auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.hda"); - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCHD, device->GetType()); EXPECT_TRUE(device->SupportsFile()); @@ -179,8 +176,6 @@ void TestRemovableDrive(PbDeviceType type, const string& filename, const string& { DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, filename); - const unordered_map params; - device->Init(params); EXPECT_NE(nullptr, device); EXPECT_EQ(type, device->GetType()); @@ -218,10 +213,6 @@ TEST(DeviceFactoryTest, SCCD_Device_Defaults) DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.iso"); - - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCCD, device->GetType()); EXPECT_TRUE(device->SupportsFile()); @@ -247,10 +238,6 @@ TEST(DeviceFactoryTest, SCBR_Device_Defaults) DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, "bridge"); - - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCBR, device->GetType()); EXPECT_FALSE(device->SupportsFile()); @@ -276,10 +263,6 @@ TEST(DeviceFactoryTest, SCDP_Device_Defaults) DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, "daynaport"); - - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCDP, device->GetType()); EXPECT_FALSE(device->SupportsFile()); @@ -304,10 +287,6 @@ TEST(DeviceFactoryTest, SCHS_Device_Defaults) DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, "services"); - - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCHS, device->GetType()); EXPECT_FALSE(device->SupportsFile()); @@ -333,10 +312,6 @@ TEST(DeviceFactoryTest, SCLP_Device_Defaults) DeviceFactory device_factory; auto device = device_factory.CreateDevice(UNDEFINED, 0, "printer"); - - const unordered_map params; - device->Init(params); - EXPECT_NE(nullptr, device); EXPECT_EQ(SCLP, device->GetType()); EXPECT_FALSE(device->SupportsFile()); diff --git a/cpp/test/protobuf_util_test.cpp b/cpp/test/protobuf_util_test.cpp index d1a4359d..ea2a21d1 100644 --- a/cpp/test/protobuf_util_test.cpp +++ b/cpp/test/protobuf_util_test.cpp @@ -106,3 +106,40 @@ TEST(ProtobufUtil, ListDevices) EXPECT_NE(string::npos, device_list.find("Host Services")); EXPECT_NE(string::npos, device_list.find("SCSI Printer")); } + +TEST(ProtobufUtil, SetProductData) +{ + PbDeviceDefinition device; + + SetProductData(device, ""); + EXPECT_EQ("", device.vendor()); + EXPECT_EQ("", device.product()); + EXPECT_EQ("", device.revision()); + + SetProductData(device, "vendor"); + EXPECT_EQ("vendor", device.vendor()); + EXPECT_EQ("", device.product()); + EXPECT_EQ("", device.revision()); + + SetProductData(device, "vendor:product"); + EXPECT_EQ("vendor", device.vendor()); + EXPECT_EQ("product", device.product()); + EXPECT_EQ("", device.revision()); + + SetProductData(device, "vendor:product:revision"); + EXPECT_EQ("vendor", device.vendor()); + EXPECT_EQ("product", device.product()); + EXPECT_EQ("revision", device.revision()); +} + +TEST(ProtobufUtil, SetIdAndLun) +{ + PbDeviceDefinition device; + + EXPECT_NE("", SetIdAndLun(device, "", 32)); + EXPECT_EQ("", SetIdAndLun(device, "1", 32)); + EXPECT_EQ(1, device.id()); + EXPECT_EQ("", SetIdAndLun(device, "2:0", 32)); + EXPECT_EQ(2, device.id()); + EXPECT_EQ(0, device.unit()); +} diff --git a/cpp/test/rasutil_test.cpp b/cpp/test/rasutil_test.cpp index 211704a8..7d607234 100644 --- a/cpp/test/rasutil_test.cpp +++ b/cpp/test/rasutil_test.cpp @@ -19,6 +19,42 @@ using namespace std; using namespace rascsi_interface; using namespace ras_util; +TEST(RasUtilTest, ProcessId) +{ + int id = -1; + int lun = -1; + + string error = ProcessId("", 32, id, lun); + EXPECT_FALSE(error.empty()); + EXPECT_EQ(-1, id); + EXPECT_EQ(-1, lun); + + error = ProcessId("0:32", 32, id, lun); + EXPECT_FALSE(error.empty()); + EXPECT_EQ(-1, id); + EXPECT_EQ(-1, lun); + + error = ProcessId("-1:", 32, id, lun); + EXPECT_FALSE(error.empty()); + EXPECT_EQ(-1, id); + EXPECT_EQ(-1, lun); + + error = ProcessId("0:-1", 32, id, lun); + EXPECT_FALSE(error.empty()); + EXPECT_EQ(-1, id); + EXPECT_EQ(-1, lun); + + error = ProcessId("0", 32, id, lun); + EXPECT_TRUE(error.empty()); + EXPECT_EQ(0, id); + EXPECT_EQ(0, lun); + + error = ProcessId("7:31", 32, id, lun); + EXPECT_TRUE(error.empty()); + EXPECT_EQ(7, id); + EXPECT_EQ(31, lun); +} + TEST(RasUtilTest, GetAsUnsignedInt) { int result; diff --git a/cpp/test/scsi_command_util_test.cpp b/cpp/test/scsi_command_util_test.cpp index cd18c9ad..2071f57f 100644 --- a/cpp/test/scsi_command_util_test.cpp +++ b/cpp/test/scsi_command_util_test.cpp @@ -10,6 +10,7 @@ #include "mocks.h" #include "shared/scsi.h" #include "shared/rascsi_exceptions.h" +#include "devices/device_logger.h" #include "devices/scsi_command_util.h" using namespace scsi_command_util; @@ -17,13 +18,14 @@ using namespace scsi_command_util; TEST(ScsiCommandUtilTest, ModeSelect6) { const int LENGTH = 26; + DeviceLogger logger; vector cdb(6); vector buf(LENGTH); // PF (vendor-specific parameter format) must not fail but be ignored cdb[1] = 0x00; - ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0); + ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0); cdb[0] = 0x15; // PF (standard parameter format) @@ -32,45 +34,50 @@ TEST(ScsiCommandUtilTest, ModeSelect6) buf[9] = 0x00; buf[10] = 0x02; buf[11] = 0x00; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Requested sector size does not match current sector size"; // Page 0 buf[12] = 0x00; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Unsupported page 0 was not rejected"; // Page 3 (Format Device Page) buf[12] = 0x03; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Requested sector size does not match current sector size"; // Match the requested to the current sector size buf[24] = 0x02; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Not enough command parameters"; - ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); + ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); } TEST(ScsiCommandUtilTest, ModeSelect10) { const int LENGTH = 30; + DeviceLogger logger; vector cdb(10); vector buf(LENGTH); // PF (vendor-specific parameter format) must not fail but be ignored cdb[1] = 0x00; - ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0); + ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0); // PF (standard parameter format) cdb[1] = 0x10; @@ -78,33 +85,37 @@ TEST(ScsiCommandUtilTest, ModeSelect10) buf[13] = 0x00; buf[14] = 0x02; buf[15] = 0x00; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Requested sector size does not match current sector size"; // Page 0 buf[16] = 0x00; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Unsupported page 0 was not rejected"; // Page 3 (Format Device Page) buf[16] = 0x03; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Requested sector size does not match current sector size"; // Match the requested to the current sector size buf[28] = 0x02; - EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); }, Throws(AllOf( + EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); }, + Throws(AllOf( Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) << "Not enough command parameters"; - ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); + ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); } TEST(ScsiCommandUtilTest, EnrichFormatPage) diff --git a/doc/rascsi.1 b/doc/rascsi.1 index 102a5496..7c592786 100644 --- a/doc/rascsi.1 +++ b/doc/rascsi.1 @@ -4,7 +4,7 @@ rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins .SH SYNOPSIS .B rascsi [\fB\-F\fR \fIFOLDER\fR] -[\fB\-L\fR \fILOG_LEVEL\fR] +[\fB\-L\fR \fILOG_LEVEL[:ID:[LUN]]\fR] [\fB\-P\fR \fIACCESS_TOKEN_FILE\fR] [\fB\-R\fR \fISCAN_DEPTH\fR] [\fB\-h\fR] @@ -52,8 +52,8 @@ The optional block size, either 512, 1024, 2048 or 4096 bytes. Default size is 5 .BR \-F\fI " " \fIFOLDER The default folder for image files. For files in this folder no absolute path needs to be specified. The initial default folder is '~/images'. .TP -.BR \-L\fI " " \fILOG_LEVEL -The rascsi log level (trace, debug, info, warn, err, off). The default log level is 'info'. +.BR \-L\fI " " \fILOG_LEVEL[:ID:[LUN]] +The rascsi log level (trace, debug, info, warn, err, off). The default log level is 'info' for all devices unless a particular device ID and an optional LUN was provided. .TP .BR \-P\fI " " \fIACCESS_TOKEN_FILE Enable authentication and read the access token from the specified file. The access token file must be owned by root and must be readable by root only. diff --git a/doc/rascsi_man_page.txt b/doc/rascsi_man_page.txt index aace3a4b..26286057 100644 --- a/doc/rascsi_man_page.txt +++ b/doc/rascsi_man_page.txt @@ -6,7 +6,7 @@ NAME rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins SYNOPSIS - rascsi [-F FOLDER] [-L LOG_LEVEL] [-P ACCESS_TOKEN_FILE] [-R + rascsi [-F FOLDER] [-L LOG_LEVEL[:ID:[LUN]]] [-P ACCESS_TOKEN_FILE] [-R SCAN_DEPTH] [-h] [-n VENDOR:PRODUCT:REVISION] [-p PORT] [-r RE‐ SERVED_IDS] [-n TYPE] [-v] [-z LOCALE] [-IDn:[u] FILE] [-HDn[:u] FILE]... @@ -61,38 +61,39 @@ OPTIONS absolute path needs to be specified. The initial default folder is '~/images'. - -L LOG_LEVEL + -L LOG_LEVEL[:ID:[LUN]] The rascsi log level (trace, debug, info, warn, err, off). The - default log level is 'info'. + default log level is 'info' for all devices unless a particular + device ID and an optional LUN was provided. -P ACCESS_TOKEN_FILE - Enable authentication and read the access token from the speci‐ - fied file. The access token file must be owned by root and must + Enable authentication and read the access token from the speci‐ + fied file. The access token file must be owned by root and must be readable by root only. -R SCAN_DEPTH - Scan for image files recursively, up to a depth of SCAN_DEPTH. - Depth 0 means to ignore any folders within the default image - filder. Be careful when using this option with many sub-folders + Scan for image files recursively, up to a depth of SCAN_DEPTH. + Depth 0 means to ignore any folders within the default image + filder. Be careful when using this option with many sub-folders in the default image folder. The default depth is 1. -h Show a help page. -n VENDOR:PRODUCT:REVISION - Set the vendor, product and revision for the device, to be re‐ - turned with the INQUIRY data. A complete set of name components + Set the vendor, product and revision for the device, to be re‐ + turned with the INQUIRY data. A complete set of name components must be provided. VENDOR may have up to 8, PRODUCT up to 16, RE‐ - VISION up to 4 characters. Padding with blanks to the maxium - length is automatically applied. Once set the name of a device + VISION up to 4 characters. Padding with blanks to the maxium + length is automatically applied. Once set the name of a device cannot be changed. -p PORT The rascsi server port, default is 6868. -r RESERVED_IDS - Comma-separated list of IDs to reserve. Pass an empty list in + Comma-separated list of IDs to reserve. Pass an empty list in order to not reserve anything. -p TYPE The optional case-insen‐ - sitive device type (SAHD, SCHD, SCRM, SCCD, SCMO, SCBR, SCDP, + sitive device type (SAHD, SCHD, SCRM, SCCD, SCMO, SCBR, SCDP, SCLP, SCHS). If no type is specified for devices that support an image file, rascsi tries to derive the type from the file exten‐ sion. @@ -100,20 +101,20 @@ OPTIONS -v Display the rascsi version. -z LOCALE - Overrides the default locale for client-faces error messages. + Overrides the default locale for client-faces error messages. The client can override the locale. -IDn[:u] FILE - n is the SCSI ID number (0-7). u (0-31) is the optional LUN + n is the SCSI ID number (0-7). u (0-31) is the optional LUN (logical unit). The default LUN is 0. - FILE is the name of the image file to use for the SCSI device. + FILE is the name of the image file to use for the SCSI device. For devices that do not support an image file (SCBR, SCDP, SCLP, - SCHS) the filename may have a special meaning or a dummy name - can be provided. For SCBR and SCDP it is an optioinal priori‐ - tized list of network interfaces, an optional IP address and + SCHS) the filename may have a special meaning or a dummy name + can be provided. For SCBR and SCDP it is an optioinal priori‐ + tized list of network interfaces, an optional IP address and netmask, e.g. "interfaces=eth0,eth1,wlan0:inet=10.10.20.1/24". - For SCLP it is the print command to be used and a reservation + For SCLP it is the print command to be used and a reservation timeout in seconds, e.g. "cmd=lp -oraw %f:timeout=60". FILE is the name of the image file to use for the SCSI device. @@ -127,7 +128,7 @@ EXAMPLES rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso Launch RaSCSI with a removable SCSI drive image as ID 0 and the raw de‐ - vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter + vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter as ID 6: rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp daynaport