Added rascsi filter to limit logging to a particular device (#978)

* Support for ID and LUN parameter for the -L option in rascsi

* Added DeviceLogger class

* Removed dupiicate code

* Fixed SonarQube issues

* Added unit tests, improved code sharing

* Fixed regression (#979)
This commit is contained in:
Uwe Seimet 2022-11-11 21:08:48 +01:00 committed by GitHub
parent 4fa513090a
commit 454c61ac0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 673 additions and 409 deletions

View File

@ -7,7 +7,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "devices/primary_device.h" #include "devices/primary_device.h"
#include "abstract_controller.h" #include "abstract_controller.h"
@ -104,7 +103,6 @@ void AbstractController::ProcessPhase()
break; break;
default: default:
LOGERROR("Cannot process phase %s", BUS::GetPhaseStrRaw(GetPhase()))
throw scsi_exception(sense_key::ABORTED_COMMAND); throw scsi_exception(sense_key::ABORTED_COMMAND);
break; break;
} }
@ -136,7 +134,7 @@ bool AbstractController::HasDeviceForLun(int lun) const
int AbstractController::ExtractInitiatorId(int id_data) 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) { if (int tmp = id_data - (1 << target_id); tmp) {
initiator_id = 0; initiator_id = 0;

View File

@ -28,6 +28,8 @@ class AbstractController : public PhaseHandler, public enable_shared_from_this<A
{ {
public: public:
static inline const int UNKNOWN_INITIATOR_ID = -1;
enum class rascsi_shutdown_mode { enum class rascsi_shutdown_mode {
NONE, NONE,
STOP_RASCSI, STOP_RASCSI,

View File

@ -5,14 +5,14 @@
// //
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp) // Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker // Copyright (C) akuker
// Copyright (C) 2022 Uwe Seimet
// //
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "hal/gpiobus.h" #include "hal/gpiobus.h"
#include "hal/systimer.h" #include "hal/systimer.h"
@ -31,6 +31,8 @@ using namespace scsi_defs;
ScsiController::ScsiController(shared_ptr<ControllerManager> controller_manager, int target_id) ScsiController::ScsiController(shared_ptr<ControllerManager> controller_manager, int target_id)
: AbstractController(controller_manager, target_id, LUN_MAX) : 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 initial buffer size will default to either the default buffer size OR
// the size of an Ethernet message, whichever is larger. // the size of an Ethernet message, whichever is larger.
AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN)); AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN));
@ -55,7 +57,7 @@ BUS::phase_t ScsiController::Process(int id)
GetBus().Acquire(); GetBus().Acquire();
if (GetBus().GetRST()) { if (GetBus().GetRST()) {
LOGWARN("RESET signal received!") logger.Warn("RESET signal received!");
Reset(); Reset();
@ -64,13 +66,6 @@ BUS::phase_t ScsiController::Process(int id)
return GetPhase(); 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; initiator_id = id;
try { try {
@ -78,7 +73,7 @@ BUS::phase_t ScsiController::Process(int id)
} }
catch(const scsi_exception&) { catch(const scsi_exception&) {
// Any exception should have been handled during the phase processing // 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(); Reset();
GetBus().Reset(); GetBus().Reset();
@ -92,7 +87,7 @@ BUS::phase_t ScsiController::Process(int id)
void ScsiController::BusFree() void ScsiController::BusFree()
{ {
if (!IsBusFree()) { if (!IsBusFree()) {
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__) logger.Trace("Bus free phase");
SetPhase(BUS::phase_t::busfree); 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. // This code has to be executed in the bus free phase and thus has to be located in the controller.
switch(shutdown_mode) { switch(shutdown_mode) {
case rascsi_shutdown_mode::STOP_RASCSI: case rascsi_shutdown_mode::STOP_RASCSI:
LOGINFO("RaSCSI shutdown requested") logger.Info("RaSCSI shutdown requested");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case rascsi_shutdown_mode::STOP_PI: case rascsi_shutdown_mode::STOP_PI:
LOGINFO("Raspberry Pi shutdown requested") logger.Info("Raspberry Pi shutdown requested");
if (system("init 0") == -1) { if (system("init 0") == -1) {
LOGERROR("Raspberry Pi shutdown failed: %s", strerror(errno)) logger.Error("Raspberry Pi shutdown failed: " + string(strerror(errno)));
} }
break; break;
case rascsi_shutdown_mode::RESTART_PI: case rascsi_shutdown_mode::RESTART_PI:
LOGINFO("Raspberry Pi restart requested") logger.Info("Raspberry Pi restart requested");
if (system("init 6") == -1) { if (system("init 6") == -1) {
LOGERROR("Raspberry Pi restart failed: %s", strerror(errno)) logger.Error("Raspberry Pi restart failed: " + string(strerror(errno)));
} }
break; break;
@ -168,7 +163,7 @@ void ScsiController::Selection()
return; return;
} }
LOGTRACE("%s Selection Phase Target ID=%d", __PRETTY_FUNCTION__, GetTargetId()) logger.Trace("Selection phase");
SetPhase(BUS::phase_t::selection); SetPhase(BUS::phase_t::selection);
@ -191,7 +186,7 @@ void ScsiController::Selection()
void ScsiController::Command() void ScsiController::Command()
{ {
if (!IsCommand()) { if (!IsCommand()) {
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__) logger.Trace("Command phase");
SetPhase(BUS::phase_t::command); SetPhase(BUS::phase_t::command);
@ -201,7 +196,9 @@ void ScsiController::Command()
const int actual_count = GetBus().CommandHandShake(GetBuffer()); const int actual_count = GetBus().CommandHandShake(GetBuffer());
if (actual_count == 0) { 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); Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
return; return;
@ -211,21 +208,19 @@ void ScsiController::Command()
// If not able to receive all, move to the status phase // If not able to receive all, move to the status phase
if (actual_count != command_byte_count) { if (actual_count != command_byte_count) {
LOGERROR("Command byte count mismatch for command $%02X: expected %d bytes, received %d byte(s)", stringstream s;
GetBuffer()[0], command_byte_count, actual_count) 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); Error(sense_key::ABORTED_COMMAND);
return; return;
} }
AllocateCmd(command_byte_count);
// Command data transfer // Command data transfer
stringstream s; AllocateCmd(command_byte_count);
for (int i = 0; i < command_byte_count; i++) { for (int i = 0; i < command_byte_count; i++) {
GetCmd()[i] = GetBuffer()[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); SetLength(0);
@ -235,7 +230,13 @@ void ScsiController::Command()
void ScsiController::Execute() void ScsiController::Execute()
{ {
LOGDEBUG("++++ CMD ++++ Executing command $%02X", static_cast<int>(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<uint8_t>(GetOpcode())); i++) {
s << setw(2) << GetCmd(i);
}
logger.Debug(s.str());
// Initialization for data transfer // Initialization for data transfer
ResetOffset(); ResetOffset();
@ -250,7 +251,7 @@ void ScsiController::Execute()
int lun = GetEffectiveLun(); int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun)) { if (!HasDeviceForLun(lun)) {
if (GetOpcode() != scsi_command::eCmdInquiry && GetOpcode() != scsi_command::eCmdRequestSense) { 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); Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
@ -264,7 +265,7 @@ void ScsiController::Execute()
// SCSI-2 4.4.3 Incorrect logical unit handling // SCSI-2 4.4.3 Incorrect logical unit handling
if (GetOpcode() == scsi_command::eCmdInquiry && !HasDeviceForLun(lun)) { 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; GetBuffer().data()[0] = 0x7f;
@ -295,13 +296,16 @@ void ScsiController::Status()
{ {
if (!IsStatus()) { if (!IsStatus()) {
// Minimum execution time // Minimum execution time
// TODO Why is a delay needed? Is this covered by the SCSI specification?
if (execstart > 0) { if (execstart > 0) {
Sleep(); Sleep();
} else { } else {
SysTimer::SleepUsec(5); SysTimer::SleepUsec(5);
} }
LOGTRACE("%s Status Phase, status is $%02X",__PRETTY_FUNCTION__, static_cast<int>(GetStatus())) stringstream s;
s << "Status Phase, status is $" << setfill('0') << setw(2) << hex << static_cast<int>(GetStatus());
logger.Trace(s.str());
SetPhase(BUS::phase_t::status); SetPhase(BUS::phase_t::status);
@ -325,7 +329,7 @@ void ScsiController::Status()
void ScsiController::MsgIn() void ScsiController::MsgIn()
{ {
if (!IsMsgIn()) { if (!IsMsgIn()) {
LOGTRACE("%s Message In phase", __PRETTY_FUNCTION__) logger.Trace("Message In phase");
SetPhase(BUS::phase_t::msgin); SetPhase(BUS::phase_t::msgin);
@ -342,10 +346,8 @@ void ScsiController::MsgIn()
void ScsiController::MsgOut() void ScsiController::MsgOut()
{ {
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetTargetId())
if (!IsMsgOut()) { if (!IsMsgOut()) {
LOGTRACE("Message Out Phase") logger.Trace("Message Out phase");
// process the IDENTIFY message // process the IDENTIFY message
if (IsSelection()) { if (IsSelection()) {
@ -385,7 +387,7 @@ void ScsiController::DataIn()
return; return;
} }
LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__) logger.Trace("Entering Data In phase");
SetPhase(BUS::phase_t::datain); SetPhase(BUS::phase_t::datain);
@ -415,7 +417,7 @@ void ScsiController::DataOut()
return; return;
} }
LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__) logger.Trace("Data Out phase");
SetPhase(BUS::phase_t::dataout); SetPhase(BUS::phase_t::dataout);
@ -453,7 +455,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
int lun = GetEffectiveLun(); int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun) || asc == asc::INVALID_LUN) { if (!HasDeviceForLun(lun) || asc == asc::INVALID_LUN) {
if (!HasDeviceForLun(0)) { if (!HasDeviceForLun(0)) {
LOGERROR("No LUN 0 for device %d", GetTargetId()) logger.Error("No LUN 0");
SetStatus(status); SetStatus(status);
SetMessage(0x00); 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) { if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X", static_cast<int>(sense_key), static_cast<int>(asc)) stringstream s;
s << setfill('0') << setw(2) << hex << "Error status: Sense Key $" << static_cast<int>(sense_key)
<< ", ASC $" << static_cast<int>(asc);
logger.Debug(s.str());
// Set Sense Key and ASC for a subsequent REQUEST SENSE // Set Sense Key and ASC for a subsequent REQUEST SENSE
GetDeviceForLun(lun)->SetStatusCode((static_cast<int>(sense_key) << 16) | (static_cast<int>(asc) << 8)); GetDeviceForLun(lun)->SetStatusCode((static_cast<int>(sense_key) << 16) | (static_cast<int>(asc) << 8));
@ -476,7 +481,7 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
SetStatus(status); SetStatus(status);
SetMessage(0x00); SetMessage(0x00);
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__) logger.Trace("Error (to status phase)");
Status(); Status();
} }
@ -487,8 +492,7 @@ void ScsiController::Send()
assert(GetBus().GetIO()); assert(GetBus().GetIO());
if (HasValidLength()) { if (HasValidLength()) {
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(GetOffset()) + ", length " logger.Trace("Sending data, offset: " + to_string(GetOffset()) + ", length: " + to_string(GetLength()));
+ to_string(GetLength())).c_str())
// The delay should be taken from the respective LUN, but as there are no Daynaport drivers for // 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. // LUNs other than 0 this work-around works.
@ -505,7 +509,6 @@ void ScsiController::Send()
return; return;
} }
// Block subtraction, result initialization
DecrementBlocks(); DecrementBlocks();
bool result = true; bool result = true;
@ -513,7 +516,7 @@ void ScsiController::Send()
if (IsDataIn() && GetBlocks() != 0) { if (IsDataIn() && GetBlocks() != 0) {
// set next buffer (set offset, length) // set next buffer (set offset, length)
result = XferIn(GetBuffer()); 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 // If result FALSE, move to status phase
@ -524,14 +527,14 @@ void ScsiController::Send()
// Continue sending if block !=0 // Continue sending if block !=0
if (GetBlocks() != 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(HasValidLength());
assert(GetOffset() == 0); assert(GetOffset() == 0);
return; return;
} }
// Move to next phase // 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()) { switch (GetPhase()) {
// Message in phase // Message in phase
case BUS::phase_t::msgin: case BUS::phase_t::msgin:
@ -571,40 +574,36 @@ void ScsiController::Send()
void ScsiController::Receive() 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()) { if (IsByteTransfer()) {
ReceiveBytes(); ReceiveBytes();
return; return;
} }
LOGTRACE("%s",__PRETTY_FUNCTION__)
// REQ is low
assert(!GetBus().GetREQ());
assert(!GetBus().GetIO());
// Length != 0 if received
if (HasValidLength()) { 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<int>(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(); UpdateOffsetAndLength();
return; return;
} }
// Block subtraction, result initialization
DecrementBlocks(); DecrementBlocks();
bool result = true; bool result = true;
// Processing after receiving data (by phase) // Processing after receiving data (by phase)
LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase())) logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase())));
switch (GetPhase()) { switch (GetPhase()) {
case BUS::phase_t::dataout: case BUS::phase_t::dataout:
if (GetBlocks() == 0) { if (GetBlocks() == 0) {
@ -684,32 +683,16 @@ bool ScsiController::XferMsg(int msg)
void ScsiController::ReceiveBytes() void ScsiController::ReceiveBytes()
{ {
assert(!GetBus().GetREQ());
assert(!GetBus().GetIO());
if (HasValidLength()) { 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()); SetBytesToTransfer(GetLength());
UpdateOffsetAndLength(); UpdateOffsetAndLength();
return; return;
} }
// Result initialization
bool result = true; bool result = true;
// Processing after receiving data (by phase) // Processing after receiving data (by phase)
LOGTRACE("%s Phase: %s",__PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(GetPhase())) logger.Trace("Phase: " + string(BUS::GetPhaseStrRaw(GetPhase())));
switch (GetPhase()) { switch (GetPhase()) {
case BUS::phase_t::dataout: case BUS::phase_t::dataout:
result = XferOut(false); result = XferOut(false);
@ -804,7 +787,10 @@ void ScsiController::DataOutNonBlockOriented()
break; break;
default: default:
LOGWARN("Unexpected Data Out phase for command $%02X", static_cast<int>(GetOpcode())) stringstream s;
s << "Unexpected Data Out phase for command $" << setfill('0') << setw(2) << hex
<< static_cast<int>(GetOpcode());
logger.Warn(s.str());
break; break;
} }
} }
@ -819,7 +805,9 @@ bool ScsiController::XferIn(vector<uint8_t>& buf)
{ {
assert(IsDataIn()); assert(IsDataIn());
LOGTRACE("%s command=%02X", __PRETTY_FUNCTION__, static_cast<int>(GetOpcode())) stringstream s;
s << "Command: $" << setfill('0') << setw(2) << hex << static_cast<int>(GetOpcode());
logger.Trace(s.str());
int lun = GetEffectiveLun(); int lun = GetEffectiveLun();
if (!HasDeviceForLun(lun)) { if (!HasDeviceForLun(lun)) {
@ -930,11 +918,14 @@ bool ScsiController::XferOutBlockOriented(bool cont)
} }
case scsi_command::eCmdSetMcastAddr: case scsi_command::eCmdSetMcastAddr:
LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__) logger.Trace("Done with DaynaPort Set Multicast Address");
break; break;
default: default:
LOGWARN("Received an unexpected command ($%02X) in %s", static_cast<int>(GetOpcode()), __PRETTY_FUNCTION__) stringstream s;
s << "Received an unexpected command ($" << setfill('0') << setw(2) << hex
<< static_cast<int>(GetOpcode()) << ")";
logger.Warn(s.str());
break; break;
} }
@ -946,12 +937,12 @@ void ScsiController::ProcessCommand()
uint32_t len = GPIOBUS::GetCommandByteCount(GetBuffer()[0]); uint32_t len = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
stringstream s; stringstream s;
s << setfill('0') << setw(2) << hex; s << "CDB=$" << setfill('0') << setw(2) << hex;
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
GetCmd()[i] = GetBuffer()[i]; GetCmd()[i] = GetBuffer()[i];
s << GetCmd(i); s << GetCmd(i);
} }
LOGTRACE("%s CDB=$%s",__PRETTY_FUNCTION__, s.str().c_str()) logger.Trace(s.str());
Execute(); Execute();
} }
@ -963,13 +954,13 @@ void ScsiController::ParseMessage()
const uint8_t message_type = scsi.msb[i]; const uint8_t message_type = scsi.msb[i];
if (message_type == 0x06) { if (message_type == 0x06) {
LOGTRACE("Received ABORT message") logger.Trace("Received ABORT message");
BusFree(); BusFree();
return; return;
} }
if (message_type == 0x0C) { if (message_type == 0x0C) {
LOGTRACE("Received BUS DEVICE RESET message") logger.Trace("Received BUS DEVICE RESET message");
scsi.syncoffset = 0; scsi.syncoffset = 0;
if (auto device = GetDeviceForLun(identified_lun); device != nullptr) { if (auto device = GetDeviceForLun(identified_lun); device != nullptr) {
device->DiscardReservation(); device->DiscardReservation();
@ -980,11 +971,11 @@ void ScsiController::ParseMessage()
if (message_type >= 0x80) { if (message_type >= 0x80) {
identified_lun = static_cast<int>(message_type) & 0x1F; identified_lun = static_cast<int>(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) { if (message_type == 0x01) {
LOGTRACE("Received EXTENDED MESSAGE") logger.Trace("Received EXTENDED MESSAGE");
// Check only when synchronous transfer is possible // Check only when synchronous transfer is possible
if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) { if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) {

View File

@ -16,6 +16,7 @@
#include "shared/scsi.h" #include "shared/scsi.h"
#include "controller_manager.h" #include "controller_manager.h"
#include "devices/device_logger.h"
#include "abstract_controller.h" #include "abstract_controller.h"
#include <array> #include <array>
@ -34,8 +35,6 @@ class ScsiController : public AbstractController
// REQ/ACK offset(limited to 16) // REQ/ACK offset(limited to 16)
static const uint8_t MAX_SYNC_OFFSET = 16; static const uint8_t MAX_SYNC_OFFSET = 16;
static const int UNKNOWN_INITIATOR_ID = -1;
const int DEFAULT_BUFFER_SIZE = 0x1000; const int DEFAULT_BUFFER_SIZE = 0x1000;
using scsi_t = struct _scsi_t { using scsi_t = struct _scsi_t {
@ -88,6 +87,8 @@ public:
private: private:
DeviceLogger logger;
// Execution start time // Execution start time
uint32_t execstart = 0; uint32_t execstart = 0;

View File

@ -7,7 +7,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_version.h" #include "shared/rascsi_version.h"
#include "device.h" #include "device.h"
#include <cassert> #include <cassert>

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include "shared/log.h"
#include "generated/rascsi_interface.pb.h" #include "generated/rascsi_interface.pb.h"
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@ -72,6 +73,8 @@ class Device //NOSONAR The number of fields and methods is justified, the comple
protected: protected:
Device(PbDeviceType, int);
void SetReady(bool b) { ready = b; } void SetReady(bool b) { ready = b; }
bool IsReset() const { return reset; } bool IsReset() const { return reset; }
void SetReset(bool b) { reset = b; } void SetReset(bool b) { reset = b; }
@ -89,8 +92,6 @@ protected:
string GetParam(const string&) const; string GetParam(const string&) const;
void SetParams(const unordered_map<string, string>&); void SetParams(const unordered_map<string, string>&);
Device(PbDeviceType, int);
public: public:
virtual ~Device() = default; virtual ~Device() = default;

View File

@ -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;
}

View File

@ -0,0 +1,44 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include <string>
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;
};

View File

@ -14,10 +14,11 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "disk.h" #include "disk.h"
#include <sstream>
#include <iomanip>
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
@ -116,7 +117,7 @@ void Disk::Read(access_mode mode)
GetController()->SetBlocks(blocks); GetController()->SetBlocks(blocks);
GetController()->SetLength(Read(GetController()->GetCmd(), GetController()->GetBuffer(), start)); 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 // Set next block
GetController()->SetNext(start + 1); GetController()->SetNext(start + 1);
@ -203,10 +204,10 @@ void Disk::StartStopUnit()
const bool load = GetController()->GetCmd(4) & 0x02; const bool load = GetController()->GetCmd(4) & 0x02;
if (load) { if (load) {
LOGTRACE(start ? "Loading medium" : "Ejecting medium") GetLogger().Trace(start ? "Loading medium" : "Ejecting medium");
} }
else { else {
LOGTRACE(start ? "Starting unit" : "Stopping unit") GetLogger().Trace(start ? "Starting unit" : "Stopping unit");
SetStopped(!start); SetStopped(!start);
} }
@ -238,7 +239,7 @@ void Disk::PreventAllowMediumRemoval()
const bool lock = GetController()->GetCmd(4) & 0x01; const bool lock = GetController()->GetCmd(4) & 0x01;
LOGTRACE(lock ? "Locking medium" : "Unlocking medium") GetLogger().Trace(lock ? "Locking medium" : "Unlocking medium");
SetLocked(lock); 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); const uint64_t block = mode == RW16 ? GetInt64(GetController()->GetCmd(), 2) : GetInt32(GetController()->GetCmd(), 2);
if (block > GetBlockCount()) { if (block > GetBlockCount()) {
LOGTRACE("%s", ("Capacity of " + to_string(GetBlockCount()) + " block(s) exceeded: Trying to access block " GetLogger().Trace("Capacity of " + to_string(GetBlockCount()) + " block(s) exceeded: Trying to access block "
+ to_string(block)).c_str()) + to_string(block));
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
} }
} }
@ -651,13 +652,14 @@ tuple<bool, uint64_t, uint32_t> Disk::CheckAndGetStartAndCount(access_mode mode)
} }
} }
LOGTRACE("%s READ/WRITE/VERIFY/SEEK command record=$%08X blocks=%d", __PRETTY_FUNCTION__, stringstream s;
static_cast<uint32_t>(start), count) s << "READ/WRITE/VERIFY/SEEK, start block: $" << setfill('0') << setw(8) << hex << start;
GetLogger().Trace(s.str() + ", blocks: " + to_string(count));
// Check capacity // Check capacity
if (uint64_t capacity = GetBlockCount(); !capacity || start > capacity || start + count > 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 " GetLogger().Trace("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
+ to_string(start) + ", block count " + to_string(count)).c_str()) + to_string(start) + ", block count " + to_string(count));
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
} }

View File

@ -75,7 +75,7 @@ bool DiskTrack::Load(const string& path)
if (dt.buffer == nullptr) { if (dt.buffer == nullptr) {
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { 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; dt.length = length;
} }
@ -88,7 +88,7 @@ bool DiskTrack::Load(const string& path)
if (dt.length != static_cast<uint32_t>(length)) { if (dt.length != static_cast<uint32_t>(length)) {
free(dt.buffer); free(dt.buffer);
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { 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; dt.length = length;
} }
@ -219,8 +219,6 @@ bool DiskTrack::ReadSector(vector<uint8_t>& buf, int sec) const
{ {
assert(sec >= 0 && sec < 0x100); assert(sec >= 0 && sec < 0x100);
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
// Error if not initialized // Error if not initialized
if (!dt.init) { if (!dt.init) {
return false; return false;

View File

@ -9,11 +9,12 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "mode_page_device.h" #include "mode_page_device.h"
#include <cstddef> #include <cstddef>
#include <sstream>
#include <iomanip>
using namespace std; using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
@ -43,14 +44,17 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<uint8_t>& buf, i
// Get page code (0x3f means all pages) // Get page code (0x3f means all pages)
const int page = cdb[2] & 0x3f; 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 // 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;
SetUpModePages(pages, page, changeable); SetUpModePages(pages, page, changeable);
if (pages.empty()) { 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); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }

View File

@ -7,10 +7,11 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "primary_device.h" #include "primary_device.h"
#include <sstream>
#include <iomanip>
using namespace std; using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
@ -41,13 +42,17 @@ void PrimaryDevice::AddCommand(scsi_command opcode, const operation& execute)
void PrimaryDevice::Dispatch(scsi_command cmd) void PrimaryDevice::Dispatch(scsi_command cmd)
{ {
stringstream s;
s << "$" << setfill('0') << setw(2) << hex << static_cast<int>(cmd);
if (const auto& it = commands.find(cmd); it != commands.end()) { if (const auto& it = commands.find(cmd); it != commands.end()) {
LOGDEBUG("Executing %s ($%02X)", command_mapping.find(cmd)->second.second, static_cast<int>(cmd)) GetLogger().Debug("Device is executing " + string(command_mapping.find(cmd)->second.second) +
" (" + s.str() + ")");
it->second(); it->second();
} }
else { else {
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetId(), GetLun(), static_cast<int>(cmd)) GetLogger().Trace("Received unsupported command: " + s.str());
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
} }
@ -63,7 +68,7 @@ void PrimaryDevice::Reset()
int PrimaryDevice::GetId() const int PrimaryDevice::GetId() const
{ {
if (GetController() == nullptr) { if (GetController() == nullptr) {
LOGERROR("Device is missing its controller") GetLogger().Error("Device is missing its controller");
} }
return GetController() != nullptr ? GetController()->GetTargetId() : -1; return GetController() != nullptr ? GetController()->GetTargetId() : -1;
@ -72,6 +77,8 @@ int PrimaryDevice::GetId() const
void PrimaryDevice::SetController(shared_ptr<AbstractController> c) void PrimaryDevice::SetController(shared_ptr<AbstractController> c)
{ {
controller = c; controller = c;
logger.SetIdAndLun(c != nullptr ? c->GetTargetId() : -1, GetLun());
} }
void PrimaryDevice::TestUnitReady() void PrimaryDevice::TestUnitReady()
@ -97,7 +104,7 @@ void PrimaryDevice::Inquiry()
// Report if the device does not support the requested LUN // Report if the device does not support the requested LUN
if (int lun = GetController()->GetEffectiveLun(); !GetController()->HasDeviceForLun(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 // Signal that the requested LUN does not exist
GetController()->GetBuffer().data()[0] = 0x7f; GetController()->GetBuffer().data()[0] = 0x7f;
@ -183,25 +190,24 @@ void PrimaryDevice::CheckReady()
// Not ready if reset // Not ready if reset
if (IsReset()) { if (IsReset()) {
SetReset(false); 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); throw scsi_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET);
} }
// Not ready if it needs attention // Not ready if it needs attention
if (IsAttn()) { if (IsAttn()) {
SetAttn(false); 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); throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
} }
// Return status if not ready // Return status if not ready
if (!IsReady()) { 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); throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
} }
// Initialization with no error GetLogger().Trace("Device is ready");
LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__)
} }
vector<uint8_t> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const vector<uint8_t> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bool is_removable) const
@ -246,15 +252,19 @@ vector<byte> PrimaryDevice::HandleRequestSense() const
buf[12] = (byte)(GetStatusCode() >> 8); buf[12] = (byte)(GetStatusCode() >> 8);
buf[13] = (byte)GetStatusCode(); buf[13] = (byte)GetStatusCode();
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, static_cast<int>(GetController()->GetStatus()), stringstream s;
static_cast<int>(buf[2]), static_cast<int>(buf[12])) s << setfill('0') << setw(2) << hex
<< "Status $" << static_cast<int>(GetController()->GetStatus())
<< ", Sense Key $" << static_cast<int>(buf[2])
<< ", ASC $" << static_cast<int>(buf[12]);
GetLogger().Trace(s.str());
return buf; return buf;
} }
bool PrimaryDevice::WriteByteSequence(vector<uint8_t>&, uint32_t) bool PrimaryDevice::WriteByteSequence(vector<uint8_t>&, 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; return false;
} }
@ -264,10 +274,10 @@ void PrimaryDevice::ReserveUnit()
reserving_initiator = GetController()->GetInitiatorId(); reserving_initiator = GetController()->GetInitiatorId();
if (reserving_initiator != -1) { 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 { else {
LOGTRACE("Reserved device ID %d, LUN %d for unknown initiator", GetId(), GetLun()) GetLogger().Trace("Reserved device for unknown initiator");
} }
EnterStatusPhase(); EnterStatusPhase();
@ -276,10 +286,10 @@ void PrimaryDevice::ReserveUnit()
void PrimaryDevice::ReleaseUnit() void PrimaryDevice::ReleaseUnit()
{ {
if (reserving_initiator != -1) { 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 { else {
LOGTRACE("Released device ID %d, LUN %d reserved by unknown initiator", GetId(), GetLun()) GetLogger().Trace("Released device reserved by unknown initiator");
} }
DiscardReservation(); DiscardReservation();
@ -303,10 +313,10 @@ bool PrimaryDevice::CheckReservation(int initiator_id, scsi_command cmd, bool pr
} }
if (initiator_id != -1) { 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 { 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; return false;

View File

@ -15,6 +15,7 @@
#include "interfaces/scsi_primary_commands.h" #include "interfaces/scsi_primary_commands.h"
#include "controllers/abstract_controller.h" #include "controllers/abstract_controller.h"
#include "device.h" #include "device.h"
#include "device_logger.h"
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
@ -56,6 +57,8 @@ protected:
void AddCommand(scsi_command, const operation&); void AddCommand(scsi_command, const operation&);
const DeviceLogger& GetLogger() const { return logger; }
vector<uint8_t> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const; vector<uint8_t> HandleInquiry(scsi_defs::device_type, scsi_level, bool) const;
virtual vector<uint8_t> InquiryInternal() const = 0; virtual vector<uint8_t> InquiryInternal() const = 0;
void CheckReady(); void CheckReady();
@ -83,6 +86,8 @@ private:
vector<byte> HandleRequestSense() const; vector<byte> HandleRequestSense() const;
DeviceLogger logger;
weak_ptr<AbstractController> controller; weak_ptr<AbstractController> controller;
unordered_map<scsi_command, operation> commands; unordered_map<scsi_command, operation> commands;

View File

@ -7,14 +7,18 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "device_logger.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include <cstring>
#include <cassert>
#include <sstream>
#include <iomanip>
using namespace scsi_defs; using namespace scsi_defs;
void scsi_command_util::ModeSelect(scsi_command cmd, const vector<int>& cdb, const vector<uint8_t>& buf, int length, void scsi_command_util::ModeSelect(const DeviceLogger& logger, scsi_command cmd, const vector<int>& cdb,
int sector_size) const vector<uint8_t>& buf, int length, int sector_size)
{ {
assert(cmd == scsi_command::eCmdModeSelect6 || cmd == scsi_command::eCmdModeSelect10); assert(cmd == scsi_command::eCmdModeSelect6 || cmd == scsi_command::eCmdModeSelect10);
assert(length >= 0); assert(length >= 0);
@ -52,14 +56,16 @@ void scsi_command_util::ModeSelect(scsi_command cmd, const vector<int>& cdb, con
if (GetInt16(buf, offset + 12) != sector_size) { if (GetInt16(buf, offset + 12) != sector_size) {
// With rascsi it is not possible to permanently (by formatting) change the 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 // 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); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
} }
has_valid_page_code = true; has_valid_page_code = true;
} }
else { 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 // Advance to the next page

View File

@ -17,9 +17,11 @@
using namespace std; using namespace std;
class DeviceLogger;
namespace scsi_command_util namespace scsi_command_util
{ {
void ModeSelect(scsi_defs::scsi_command, const vector<int>&, const vector<uint8_t>&, int, int); void ModeSelect(const DeviceLogger&, scsi_defs::scsi_command, const vector<int>&, const vector<uint8_t>&, int, int);
void EnrichFormatPage(map<int, vector<byte>>&, bool, int); void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
void AddAppleVendorModePage(map<int, vector<byte>>&, bool); void AddAppleVendorModePage(map<int, vector<byte>>&, bool);

View File

@ -24,14 +24,20 @@
// Note: This requires a DaynaPort SCSI Link driver. // Note: This requires a DaynaPort SCSI Link driver.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "scsi_daynaport.h" #include "scsi_daynaport.h"
#include <sstream>
#include <iomanip>
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
SCSIDaynaPort::SCSIDaynaPort(int lun) : PrimaryDevice(SCDP, lun)
{
SupportsParams(true);
}
bool SCSIDaynaPort::Init(const unordered_map<string, string>& params) bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
{ {
PrimaryDevice::Init(params); PrimaryDevice::Init(params);
@ -48,18 +54,16 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
// In the MacOS driver, it looks like the driver is doing two "READ" system calls. // In the MacOS driver, it looks like the driver is doing two "READ" system calls.
SetSendDelay(DAYNAPORT_READ_HEADER_SZ); SetSendDelay(DAYNAPORT_READ_HEADER_SZ);
SupportsParams(true);
m_bTapEnable = m_tap.Init(GetParams()); m_bTapEnable = m_tap.Init(GetParams());
if(!m_bTapEnable){ 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 // Not terminating on regular Linux PCs is helpful for testing
#if !defined(__x86_64__) && !defined(__X86__) #if !defined(__x86_64__) && !defined(__X86__)
return false; return false;
#endif #endif
} else { } else {
LOGDEBUG("Tap interface created") GetLogger().Trace("Tap interface created");
} }
Reset(); Reset();
@ -118,7 +122,8 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, vector<uint8_t>& buf, uint64_t)
const auto response = (scsi_resp_read_t*)buf.data(); const auto response = (scsi_resp_read_t*)buf.data();
const int requested_length = cdb[4]; 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. // 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. // We should respond by going into the status mode with a code of 0x02.
@ -141,13 +146,13 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, vector<uint8_t>& buf, uint64_t)
// If we didn't receive anything, return size of 0 // If we didn't receive anything, return size of 0
if (rx_packet_size <= 0) { if (rx_packet_size <= 0) {
LOGTRACE("%s No packet received", __PRETTY_FUNCTION__) GetLogger().Trace("No packet received");
response->length = 0; response->length = 0;
response->flags = read_data_flags_t::e_no_more_data; response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ; 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 // This is a very basic filter to prevent unnecessary packets from
// being sent to the SCSI initiator. // being sent to the SCSI initiator.
@ -177,14 +182,12 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, vector<uint8_t>& buf, uint64_t)
// configuration from SCSI command 0x0D // configuration from SCSI command 0x0D
if (!send_message_to_host) { if (!send_message_to_host) {
LOGDEBUG("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", \ stringstream s;
__PRETTY_FUNCTION__, s << "Received a packet that's not for me:" << setfill('0') << setw(2) << hex;
static_cast<int>(response->data[0]), for (int i = 0 ; i < 6; i++) {
static_cast<int>(response->data[1]), s << " $" << static_cast<int>(response->data[i]);
static_cast<int>(response->data[2]), }
static_cast<int>(response->data[3]), GetLogger().Debug(s.str());
static_cast<int>(response->data[4]),
static_cast<int>(response->data[5]))
// If there are pending packets to be processed, we'll tell the host that the read // If there are pending packets to be processed, we'll tell the host that the read
// length was 0. // length was 0.
@ -253,16 +256,18 @@ bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, vector<uint8_t>& buf, uin
if (data_format == 0x00) { if (data_format == 0x00) {
m_tap.Send(buf.data(), data_length); 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) { else if (data_format == 0x80) {
// The data length is specified in the first 2 bytes of the payload // The data length is specified in the first 2 bytes of the payload
data_length = buf[1] + ((static_cast<int>(buf[0]) & 0xff) << 8); data_length = buf[1] + ((static_cast<int>(buf[0]) & 0xff) << 8);
m_tap.Send(&(buf.data()[4]), data_length); 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 { 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); GetController()->SetBlocks(0);
@ -308,15 +313,16 @@ void SCSIDaynaPort::Read6()
// If any commands have a bogus control value, they were probably not // If any commands have a bogus control value, they were probably not
// generated by the DaynaPort driver so ignore them // generated by the DaynaPort driver so ignore them
if (GetController()->GetCmd(5) != 0xc0 && GetController()->GetCmd(5) != 0x80) { if (GetController()->GetCmd(5) != 0xc0 && GetController()->GetCmd(5) != 0x80) {
LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, GetLogger().Trace("Control value: " + to_string(GetController()->GetCmd(5)));
GetController()->GetCmd(5), GetController()->GetCmd(5))
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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)); 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 // Set next block
GetController()->SetNext(record + 1); GetController()->SetNext(record + 1);
@ -338,10 +344,14 @@ void SCSIDaynaPort::Write6() const
GetController()->SetLength(GetInt16(GetController()->GetCmd(), 3) + 8); GetController()->SetLength(GetInt16(GetController()->GetCmd(), 3) + 8);
} }
else { 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) { if (GetController()->GetLength() <= 0) {
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); 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())); GetController()->SetLength(RetrieveStats(GetController()->GetCmd(), GetController()->GetBuffer()));
switch(GetController()->GetCmd(5)){ switch(GetController()->GetCmd(5)){
case CMD_SCSILINK_SETMODE: case CMD_SCSILINK_SETMODE:
// TODO Not implemented, do nothing // Not implemented, do nothing
EnterStatusPhase(); EnterStatusPhase();
break; break;
@ -407,15 +417,10 @@ void SCSIDaynaPort::SetInterfaceMode() const
EnterDataOutPhase(); EnterDataOutPhase();
break; 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: 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); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
break; break;
} }
@ -425,8 +430,9 @@ void SCSIDaynaPort::SetMcastAddr() const
{ {
GetController()->SetLength(GetController()->GetCmd(4)); GetController()->SetLength(GetController()->GetCmd(4));
if (GetController()->GetLength() == 0) { 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); 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 (GetController()->GetCmd(5) & 0x80) {
if (!m_tap.Enable()) { 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); throw scsi_exception(sense_key::ABORTED_COMMAND);
} }
m_tap.Flush(); m_tap.Flush();
LOGINFO("The DaynaPort interface has been ENABLED") GetLogger().Info("The DaynaPort interface has been ENABLED");
} }
else { else {
if (!m_tap.Disable()) { 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); throw scsi_exception(sense_key::ABORTED_COMMAND);
} }
LOGINFO("The DaynaPort interface has been DISABLED") GetLogger().Info("The DaynaPort interface has been DISABLED");
} }
EnterStatusPhase(); EnterStatusPhase();

View File

@ -45,7 +45,7 @@ class SCSIDaynaPort : public PrimaryDevice, public ByteWriter
{ {
public: public:
explicit SCSIDaynaPort(int lun) : PrimaryDevice(SCDP, lun) {} explicit SCSIDaynaPort(int);
~SCSIDaynaPort() override = default; ~SCSIDaynaPort() override = default;
bool Init(const unordered_map<string, string>&) override; bool Init(const unordered_map<string, string>&) override;

View File

@ -16,7 +16,6 @@
// work with the Sharp X68000 operating system. // work with the Sharp X68000 operating system.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "scsi_host_bridge.h" #include "scsi_host_bridge.h"
@ -27,6 +26,11 @@ using namespace std;
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
SCSIBR::SCSIBR(int lun) : PrimaryDevice(SCBR, lun)
{
SupportsParams(true);
}
bool SCSIBR::Init(const unordered_map<string, string>& params) bool SCSIBR::Init(const unordered_map<string, string>& params)
{ {
PrimaryDevice::Init(params); PrimaryDevice::Init(params);
@ -38,13 +42,11 @@ bool SCSIBR::Init(const unordered_map<string, string>& params)
AddCommand(scsi_command::eCmdGetMessage10, [this] { GetMessage10(); }); AddCommand(scsi_command::eCmdGetMessage10, [this] { GetMessage10(); });
AddCommand(scsi_command::eCmdSendMessage10, [this] { SendMessage10(); }); AddCommand(scsi_command::eCmdSendMessage10, [this] { SendMessage10(); });
SupportsParams(true);
#ifdef __linux__ #ifdef __linux__
// TAP Driver Generation // TAP Driver Generation
m_bTapEnable = tap.Init(GetParams()); m_bTapEnable = tap.Init(GetParams());
if (!m_bTapEnable){ if (!m_bTapEnable){
LOGERROR("Unable to open the TAP interface") GetLogger().Error("Unable to open the TAP interface");
return false; return false;
} }
#endif #endif

View File

@ -32,7 +32,7 @@ class SCSIBR : public PrimaryDevice, public ByteWriter
public: public:
explicit SCSIBR(int lun) : PrimaryDevice(SCBR, lun) {} explicit SCSIBR(int);
~SCSIBR() override = default; ~SCSIBR() override = default;
bool Init(const unordered_map<string, string>&) override; bool Init(const unordered_map<string, string>&) override;

View File

@ -29,7 +29,6 @@
// With STOP PRINT printing can be cancelled before SYNCHRONIZE BUFFER was sent. // With STOP PRINT printing can be cancelled before SYNCHRONIZE BUFFER was sent.
// //
#include "shared/log.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "scsi_printer.h" #include "scsi_printer.h"
@ -41,6 +40,11 @@ using namespace filesystem;
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
SCSIPrinter::SCSIPrinter(int lun) : PrimaryDevice(SCLP, lun)
{
SupportsParams(true);
}
bool SCSIPrinter::Init(const unordered_map<string, string>& params) bool SCSIPrinter::Init(const unordered_map<string, string>& params)
{ {
PrimaryDevice::Init(params); PrimaryDevice::Init(params);
@ -57,7 +61,7 @@ bool SCSIPrinter::Init(const unordered_map<string, string>& params)
AddCommand(scsi_command::eCmdSendDiagnostic, [this] { SendDiagnostic(); }); AddCommand(scsi_command::eCmdSendDiagnostic, [this] { SendDiagnostic(); });
if (GetParam("cmd").find("%f") == string::npos) { if (GetParam("cmd").find("%f") == string::npos) {
LOGERROR("Missing filename specifier %%f") GetLogger().Trace("Missing filename specifier %f");
return false; return false;
} }
@ -65,7 +69,6 @@ bool SCSIPrinter::Init(const unordered_map<string, string>& params)
file_template = temp_directory_path(error); //NOSONAR Publicly writable directory is fine here file_template = temp_directory_path(error); //NOSONAR Publicly writable directory is fine here
file_template += PRINTER_FILE_PATTERN; file_template += PRINTER_FILE_PATTERN;
SupportsParams(true);
SetReady(true); SetReady(true);
return true; return true;
@ -86,11 +89,11 @@ void SCSIPrinter::Print()
{ {
const uint32_t length = GetInt24(GetController()->GetCmd(), 2); 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()) { if (length > GetController()->GetBuffer().size()) {
LOGERROR("%s", ("Transfer buffer overflow: Buffer size is " + to_string(GetController()->GetBuffer().size()) + GetLogger().Error("Transfer buffer overflow: Buffer size is " + to_string(GetController()->GetBuffer().size()) +
" bytes, " + to_string(length) + " bytes expected").c_str()) " bytes, " + to_string(length) + " bytes expected");
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB); throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
} }
@ -104,7 +107,7 @@ void SCSIPrinter::Print()
void SCSIPrinter::SynchronizeBuffer() void SCSIPrinter::SynchronizeBuffer()
{ {
if (!out.is_open()) { if (!out.is_open()) {
LOGWARN("Nothing to print") GetLogger().Warn("Nothing to print");
throw scsi_exception(sense_key::ABORTED_COMMAND); throw scsi_exception(sense_key::ABORTED_COMMAND);
} }
@ -116,12 +119,12 @@ void SCSIPrinter::SynchronizeBuffer()
error_code error; 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())) { 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(); Cleanup();
@ -142,7 +145,7 @@ bool SCSIPrinter::WriteByteSequence(vector<uint8_t>& buf, uint32_t length)
// There is no C++ API that generates a file with a unique name // There is no C++ API that generates a file with a unique name
const int fd = mkstemp(f.data()); const int fd = mkstemp(f.data());
if (fd == -1) { 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; return false;
} }
close(fd); close(fd);
@ -154,10 +157,10 @@ bool SCSIPrinter::WriteByteSequence(vector<uint8_t>& buf, uint32_t length)
throw scsi_exception(sense_key::ABORTED_COMMAND); 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); out.write((const char*)buf.data(), length);

View File

@ -26,7 +26,7 @@ class SCSIPrinter : public PrimaryDevice, private ScsiPrinterCommands
public: public:
explicit SCSIPrinter(int lun) : PrimaryDevice(SCLP, lun) {} explicit SCSIPrinter(int);
~SCSIPrinter() override = default; ~SCSIPrinter() override = default;
bool Init(const unordered_map<string, string>&) override; bool Init(const unordered_map<string, string>&) override;

View File

@ -26,6 +26,10 @@ using namespace scsi_command_util;
SCSICD::SCSICD(int lun, const unordered_set<uint32_t>& sector_sizes) : Disk(SCCD, lun) SCSICD::SCSICD(int lun, const unordered_set<uint32_t>& sector_sizes) : Disk(SCCD, lun)
{ {
SetSectorSizes(sector_sizes); SetSectorSizes(sector_sizes);
SetReadOnly(true);
SetRemovable(true);
SetLockable(true);
} }
bool SCSICD::Init(const unordered_map<string, string>& params) bool SCSICD::Init(const unordered_map<string, string>& params)
@ -34,10 +38,6 @@ bool SCSICD::Init(const unordered_map<string, string>& params)
AddCommand(scsi_command::eCmdReadToc, [this] { ReadToc(); }); AddCommand(scsi_command::eCmdReadToc, [this] { ReadToc(); });
SetReadOnly(true);
SetRemovable(true);
SetLockable(true);
return true; return true;
} }

View File

@ -86,7 +86,7 @@ vector<uint8_t> SCSIHD::InquiryInternal() const
void SCSIHD::ModeSelect(scsi_command cmd, const vector<int>& cdb, const vector<uint8_t>& buf, int length) const void SCSIHD::ModeSelect(scsi_command cmd, const vector<int>& cdb, const vector<uint8_t>& 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<int, vector<byte>>& pages, bool changeable) const void SCSIHD::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const

View File

@ -91,7 +91,7 @@ void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
void SCSIMO::ModeSelect(scsi_command cmd, const vector<int>& cdb, const vector<uint8_t>& buf, int length) const void SCSIMO::ModeSelect(scsi_command cmd, const vector<int>& cdb, const vector<uint8_t>& 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());
} }
// //

View File

@ -26,9 +26,6 @@
using namespace std; using namespace std;
using namespace ras_util; 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) void ScsiMon::KillHandler(int)
{ {
running = false; running = false;
@ -75,19 +72,6 @@ void ScsiMon::ParseArguments(const vector<char *>& args)
html_file_name += ".html"; 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<char *>& args) const void ScsiMon::PrintHelpText(const vector<char *>& args) const
{ {
LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0]) LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0])
@ -174,7 +158,8 @@ int ScsiMon::run(const vector<char *>& args)
#endif #endif
spdlog::set_pattern("%^[%l]%$ %v"); spdlog::set_pattern("%^[%l]%$ %v");
PrintCopyrightText(); ras_util::Banner("SCSI Monitor Capture Tool");
ParseArguments(args); ParseArguments(args);
#ifdef DEBUG #ifdef DEBUG

View File

@ -26,10 +26,11 @@ public:
int run(const vector<char *>&); int run(const vector<char *>&);
inline static double ns_per_loop;
private: private:
void ParseArguments(const vector<char *>&); void ParseArguments(const vector<char *>&);
void PrintCopyrightText() const;
void PrintHelpText(const vector<char *>&) const; void PrintHelpText(const vector<char *>&) const;
void Banner() const; void Banner() const;
bool Init(); bool Init();
@ -57,5 +58,4 @@ private:
string json_file_name; string json_file_name;
string html_file_name; string html_file_name;
string input_file_name; string input_file_name;
}; };

View File

@ -12,6 +12,7 @@
#include "shared/log.h" #include "shared/log.h"
#include "hal/gpiobus.h" #include "hal/gpiobus.h"
#include "data_sample.h" #include "data_sample.h"
#include "sm_core.h"
#include "sm_reports.h" #include "sm_reports.h"
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
@ -50,8 +51,6 @@ const int PIN_PHASE = 0;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static uint8_t prev_value[32] = {0xFF}; static uint8_t prev_value[32] = {0xFF};
extern double ns_per_loop;
static uint8_t get_pin_value(uint32_t data, int pin) static uint8_t get_pin_value(uint32_t data, int pin)
{ {
return (data >> pin) & 1; return (data >> pin) & 1;
@ -164,7 +163,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
uint32_t i = 0; uint32_t i = 0;
while (i < capture_count) { 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_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_SEL, SYMBOL_PIN_SEL);
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD);

View File

@ -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) void Rascsi::TerminationHandler(int signum)
{ {
Cleanup(); Cleanup();
@ -216,12 +228,11 @@ Rascsi::optargs_type Rascsi::ParseArguments(const vector<char *>& args, int& por
void Rascsi::CreateInitialDevices(const optargs_type& optargs) const void Rascsi::CreateInitialDevices(const optargs_type& optargs) const
{ {
PbCommand command; PbCommand command;
int id = -1;
int lun = -1;
PbDeviceType type = UNDEFINED; PbDeviceType type = UNDEFINED;
int block_size = 0; int block_size = 0;
string name; string name;
string log_level; string log_level;
string id_and_lun;
const char *locale = setlocale(LC_MESSAGES, ""); const char *locale = setlocale(LC_MESSAGES, "");
if (locale == nullptr || !strcmp(locale, "C")) { if (locale == nullptr || !strcmp(locale, "C")) {
@ -233,15 +244,12 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const
switch (option) { switch (option) {
case 'i': case 'i':
case 'I': case 'I':
id = -1;
lun = -1;
continue; continue;
case 'd': case 'd':
case 'D': { case 'D':
ProcessId(value, ScsiController::LUN_MAX, id, lun); id_and_lun = value;
continue; continue;
}
case 'z': case 'z':
locale = value.c_str(); locale = value.c_str();
@ -271,13 +279,8 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const
} }
continue; continue;
case 't': { case 't':
string t = value; type = ParseDeviceType(value);
transform(t.begin(), t.end(), t.begin(), ::toupper);
if (!PbDeviceType_Parse(t, &type)) {
throw parser_exception("Illegal device type '" + value + "'");
}
}
continue; continue;
case 1: case 1:
@ -288,35 +291,25 @@ void Rascsi::CreateInitialDevices(const optargs_type& optargs) const
throw parser_exception("Parser error"); throw parser_exception("Parser error");
} }
// Set up the device data
PbDeviceDefinition *device = command.add_devices(); 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_type(type);
device->set_block_size(block_size); device->set_block_size(block_size);
ParseParameters(*device, value); ParseParameters(*device, value);
if (size_t separator_pos = name.find(COMPONENT_SEPARATOR); separator_pos != string::npos) { SetProductData(*device, name);
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);
}
id = -1;
type = UNDEFINED; type = UNDEFINED;
block_size = 0; block_size = 0;
name = ""; name = "";
id_and_lun = "";
} }
// Attach all specified devices // Attach all specified devices
@ -485,7 +478,7 @@ bool Rascsi::ExecuteCommand(const CommandContext& context, const PbCommand& comm
return true; return true;
} }
int Rascsi::run(const vector<char *>& args) const int Rascsi::run(const vector<char *>& args)
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
@ -579,22 +572,14 @@ int Rascsi::run(const vector<char *>& args) const
// Wait until BSY is released as there is a possibility for the // 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) // initiator to assert it while setting the ID (for up to 3 seconds)
if (bus->GetBSY()) { WaitForNotBusy();
const uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3'000'000) {
bus->Acquire();
if (!bus->GetBSY()) {
break;
}
}
}
// Stop because the bus is busy or another device responded // Stop because the bus is busy or another device responded
if (bus->GetBSY() || !bus->GetSEL()) { if (bus->GetBSY() || !bus->GetSEL()) {
continue; continue;
} }
int initiator_id = -1; int initiator_id = AbstractController::UNKNOWN_INITIATOR_ID;
// The initiator and target ID // The initiator and target ID
const uint8_t id_data = bus->GetDAT(); const uint8_t id_data = bus->GetDAT();
@ -604,8 +589,17 @@ int Rascsi::run(const vector<char *>& args) const
// Identify the responsible controller // Identify the responsible controller
auto controller = controller_manager->IdentifyController(id_data); auto controller = controller_manager->IdentifyController(id_data);
if (controller != nullptr) { if (controller != nullptr) {
device_logger.SetIdAndLun(controller->GetTargetId(), -1);
initiator_id = controller->ExtractInitiatorId(id_data); 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) { if (controller->Process(initiator_id) == BUS::phase_t::selection) {
phase = BUS::phase_t::selection; phase = BUS::phase_t::selection;
} }
@ -648,3 +642,19 @@ int Rascsi::run(const vector<char *>& args) const
return EXIT_SUCCESS; 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;
}
}
}
}

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include "devices/device_logger.h"
#include "rascsi/command_context.h" #include "rascsi/command_context.h"
#include "rascsi/rascsi_service.h" #include "rascsi/rascsi_service.h"
#include "rascsi/rascsi_image.h" #include "rascsi/rascsi_image.h"
@ -34,7 +35,7 @@ public:
Rascsi() = default; Rascsi() = default;
~Rascsi() = default; ~Rascsi() = default;
int run(const vector<char *>&) const; int run(const vector<char *>&);
private: private:
@ -43,13 +44,17 @@ private:
static void Cleanup(); static void Cleanup();
void ReadAccessToken(const string&) const; void ReadAccessToken(const string&) const;
void LogDevices(string_view) const; void LogDevices(string_view) const;
PbDeviceType ParseDeviceType(const string&) const;
static void TerminationHandler(int); static void TerminationHandler(int);
optargs_type ParseArguments(const vector<char *>&, int&) const; optargs_type ParseArguments(const vector<char *>&, int&) const;
void CreateInitialDevices(const optargs_type&) const; void CreateInitialDevices(const optargs_type&) const;
void WaitForNotBusy() const;
// TODO Should not be static and should be moved to RascsiService // TODO Should not be static and should be moved to RascsiService
static bool ExecuteCommand(const CommandContext&, const PbCommand&); static bool ExecuteCommand(const CommandContext&, const PbCommand&);
DeviceLogger device_logger;
// A static instance is needed because of the signal handler // A static instance is needed because of the signal handler
static inline shared_ptr<BUS> bus; static inline shared_ptr<BUS> bus;

View File

@ -13,6 +13,7 @@
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "controllers/controller_manager.h" #include "controllers/controller_manager.h"
#include "controllers/scsi_controller.h" #include "controllers/scsi_controller.h"
#include "devices/device_logger.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include "devices/primary_device.h" #include "devices/primary_device.h"
#include "devices/disk.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 bool RascsiExecutor::SetLogLevel(const string& log_level) const
{ {
if (log_level == "trace") { int id = -1;
set_level(level::trace); 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); if (const auto& it = log_level_mapping.find(level); it != log_level_mapping.end()) {
} set_level(it->second);
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);
} }
else { else {
LOGWARN("Invalid log level '%s'", log_level.c_str()) LOGWARN("Invalid log level '%s'", log_level.c_str())
return false; 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; return true;
} }

View File

@ -9,8 +9,11 @@
#pragma once #pragma once
#include "spdlog/spdlog.h"
#include "shared/protobuf_serializer.h" #include "shared/protobuf_serializer.h"
#include "rascsi/rascsi_response.h" #include "rascsi/rascsi_response.h"
#include <unordered_set>
#include <unordered_map>
class RascsiImage; class RascsiImage;
class DeviceFactory; class DeviceFactory;
@ -18,6 +21,8 @@ class ControllerManager;
class PrimaryDevice; class PrimaryDevice;
class CommandContext; class CommandContext;
using namespace spdlog;
class RascsiExecutor class RascsiExecutor
{ {
public: public:
@ -66,4 +71,13 @@ private:
const ProtobufSerializer serializer; const ProtobufSerializer serializer;
unordered_set<int> reserved_ids; unordered_set<int> reserved_ids;
static inline const unordered_map<string, level::level_enum> log_level_mapping = {
{ "trace", level::trace },
{ "debug", level::debug },
{ "info", level::info },
{ "warn", level::warn },
{ "err", level::err },
{ "off", level::off }
};
}; };

View File

@ -5,8 +5,7 @@
// //
// Powered by XM6 TypeG Technology. // Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS // Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020-2021 Contributors to the RaSCSI project // Copyright (C) 2020-2022 Contributors to the RaSCSI project
// [ Send Control Command ]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -88,20 +87,12 @@ int RasCtl::run(const vector<char *>& args) const
while ((opt = getopt(static_cast<int>(args.size()), args.data(), while ((opt = getopt(static_cast<int>(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) { "e::lmos::vDINOTVXa:b:c:d:f:h:i:n:p:r:t:x:z:C:E:F:L:P::R:")) != -1) {
switch (opt) { switch (opt) {
case 'i': { case 'i':
int id; if (const string error = SetIdAndLun(*device, optarg, ScsiController::LUN_MAX); !error.empty()) {
int lun; cerr << "Error: " << error << endl;
try {
ProcessId(optarg, ScsiController::LUN_MAX, id, lun);
}
catch(const parser_exception& e) {
cerr << "Error: " << e.what() << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
device->set_id(id);
device->set_unit(lun);
break; break;
}
case 'C': case 'C':
command.set_operation(CREATE_IMAGE); command.set_operation(CREATE_IMAGE);
@ -206,32 +197,8 @@ int RasCtl::run(const vector<char *>& args) const
image_params = optarg; image_params = optarg;
break; break;
case 'n': { case 'n':
string vendor; SetProductData(*device, optarg);
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);
}
break; break;
case 'p': case 'p':

View File

@ -9,9 +9,12 @@
#pragma once #pragma once
#include "generated/rascsi_interface.pb.h"
#include <vector> #include <vector>
#include <string>
using namespace std; using namespace std;
using namespace rascsi_interface;
class RasCtl class RasCtl
{ {

View File

@ -107,8 +107,12 @@ void RasDump::ParseArguments(const vector<char *>& args)
break; break;
case 't': case 't': {
ProcessId(optarg, 8, target_id, target_lun); const string error = ProcessId(optarg, 8, target_id, target_lun);
if (!error.empty()) {
throw parser_exception(error);
}
}
break; break;
case 'v': case 'v':

View File

@ -14,7 +14,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <stdexcept>
using namespace std; using namespace std;

View File

@ -6,14 +6,12 @@
// Powered by XM6 TypeG Technology. // Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS // Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020 akuker // Copyright (C) 2020 akuker
// [ Logging utilities ]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/sinks/sink.h"
static const int LOGBUF_SIZE = 512; static const int LOGBUF_SIZE = 512;

View File

@ -96,6 +96,41 @@ void protobuf_util::SetPatternParams(PbCommand& command, string_view patterns)
SetParam(command, "file_pattern", file_pattern); 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<PbDevice>& pb_devices) string protobuf_util::ListDevices(const list<PbDevice>& pb_devices)
{ {
if (pb_devices.empty()) { if (pb_devices.empty()) {

View File

@ -30,5 +30,7 @@ namespace protobuf_util
void SetParam(PbDevice&, const string&, string_view); void SetParam(PbDevice&, const string&, string_view);
void SetParam(PbDeviceDefinition&, const string&, string_view); void SetParam(PbDeviceDefinition&, const string&, string_view);
void SetPatternParams(PbCommand&, string_view); void SetPatternParams(PbCommand&, string_view);
void SetProductData(PbDeviceDefinition&, const string&);
string SetIdAndLun(PbDeviceDefinition&, const string&, int);
string ListDevices(const list<PbDevice>&); string ListDevices(const list<PbDevice>&);
} }

View File

@ -7,9 +7,9 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "rascsi_exceptions.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "rasutil.h" #include "rasutil.h"
#include <cassert>
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
@ -35,19 +35,35 @@ bool ras_util::GetAsUnsignedInt(const string& value, int& result)
return true; 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 (const size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) {
if (!GetAsUnsignedInt(id_spec, id) || id >= 8) { 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; lun = 0;
} }
else if (!GetAsUnsignedInt(id_spec.substr(0, separator_pos), id) || id > 7 || else if (!GetAsUnsignedInt(id_spec.substr(0, separator_pos), id) || id > 7 ||
!GetAsUnsignedInt(id_spec.substr(separator_pos + 1), lun) || lun >= max_luns) { !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) string ras_util::Banner(const string& app)

View File

@ -19,7 +19,7 @@ namespace ras_util
static const char COMPONENT_SEPARATOR = ':'; static const char COMPONENT_SEPARATOR = ':';
bool GetAsUnsignedInt(const string&, int&); bool GetAsUnsignedInt(const string&, int&);
void ProcessId(const string&, int, int&, int&); string ProcessId(const string&, int, int&, int&);
string Banner(const string&); string Banner(const string&);
string GetExtensionLowerCase(const string&); string GetExtensionLowerCase(const string&);

View File

@ -199,14 +199,13 @@ TEST(AbstractControllerTest, ExtractInitiatorId)
{ {
const int ID = 1; const int ID = 1;
const int INITIATOR_ID = 7; const int INITIATOR_ID = 7;
const int UNKNOWN_INITIATOR_ID = -1;
auto bus = make_shared<MockBus>(); auto bus = make_shared<MockBus>();
auto controller_manager = make_shared<ControllerManager>(*bus); auto controller_manager = make_shared<ControllerManager>(*bus);
MockAbstractController controller(controller_manager, ID); MockAbstractController controller(controller_manager, ID);
EXPECT_EQ(INITIATOR_ID, controller.ExtractInitiatorId((1 << INITIATOR_ID) | ( 1 << 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) TEST(AbstractControllerTest, GetOpcode)

View File

@ -140,9 +140,6 @@ TEST(DeviceFactoryTest, SCHD_Device_Defaults)
auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.hda"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.hda");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHD, device->GetType()); EXPECT_EQ(SCHD, device->GetType());
EXPECT_TRUE(device->SupportsFile()); EXPECT_TRUE(device->SupportsFile());
@ -179,8 +176,6 @@ void TestRemovableDrive(PbDeviceType type, const string& filename, const string&
{ {
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, filename); auto device = device_factory.CreateDevice(UNDEFINED, 0, filename);
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(type, device->GetType()); EXPECT_EQ(type, device->GetType());
@ -218,10 +213,6 @@ TEST(DeviceFactoryTest, SCCD_Device_Defaults)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.iso"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.iso");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCCD, device->GetType()); EXPECT_EQ(SCCD, device->GetType());
EXPECT_TRUE(device->SupportsFile()); EXPECT_TRUE(device->SupportsFile());
@ -247,10 +238,6 @@ TEST(DeviceFactoryTest, SCBR_Device_Defaults)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "bridge"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "bridge");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCBR, device->GetType()); EXPECT_EQ(SCBR, device->GetType());
EXPECT_FALSE(device->SupportsFile()); EXPECT_FALSE(device->SupportsFile());
@ -276,10 +263,6 @@ TEST(DeviceFactoryTest, SCDP_Device_Defaults)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "daynaport"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "daynaport");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCDP, device->GetType()); EXPECT_EQ(SCDP, device->GetType());
EXPECT_FALSE(device->SupportsFile()); EXPECT_FALSE(device->SupportsFile());
@ -304,10 +287,6 @@ TEST(DeviceFactoryTest, SCHS_Device_Defaults)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "services"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "services");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHS, device->GetType()); EXPECT_EQ(SCHS, device->GetType());
EXPECT_FALSE(device->SupportsFile()); EXPECT_FALSE(device->SupportsFile());
@ -333,10 +312,6 @@ TEST(DeviceFactoryTest, SCLP_Device_Defaults)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "printer"); auto device = device_factory.CreateDevice(UNDEFINED, 0, "printer");
const unordered_map<string, string> params;
device->Init(params);
EXPECT_NE(nullptr, device); EXPECT_NE(nullptr, device);
EXPECT_EQ(SCLP, device->GetType()); EXPECT_EQ(SCLP, device->GetType());
EXPECT_FALSE(device->SupportsFile()); EXPECT_FALSE(device->SupportsFile());

View File

@ -106,3 +106,40 @@ TEST(ProtobufUtil, ListDevices)
EXPECT_NE(string::npos, device_list.find("Host Services")); EXPECT_NE(string::npos, device_list.find("Host Services"));
EXPECT_NE(string::npos, device_list.find("SCSI Printer")); 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());
}

View File

@ -19,6 +19,42 @@ using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace ras_util; 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) TEST(RasUtilTest, GetAsUnsignedInt)
{ {
int result; int result;

View File

@ -10,6 +10,7 @@
#include "mocks.h" #include "mocks.h"
#include "shared/scsi.h" #include "shared/scsi.h"
#include "shared/rascsi_exceptions.h" #include "shared/rascsi_exceptions.h"
#include "devices/device_logger.h"
#include "devices/scsi_command_util.h" #include "devices/scsi_command_util.h"
using namespace scsi_command_util; using namespace scsi_command_util;
@ -17,13 +18,14 @@ using namespace scsi_command_util;
TEST(ScsiCommandUtilTest, ModeSelect6) TEST(ScsiCommandUtilTest, ModeSelect6)
{ {
const int LENGTH = 26; const int LENGTH = 26;
DeviceLogger logger;
vector<int> cdb(6); vector<int> cdb(6);
vector<uint8_t> buf(LENGTH); vector<uint8_t> buf(LENGTH);
// PF (vendor-specific parameter format) must not fail but be ignored // PF (vendor-specific parameter format) must not fail but be ignored
cdb[1] = 0x00; cdb[1] = 0x00;
ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0); ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 0);
cdb[0] = 0x15; cdb[0] = 0x15;
// PF (standard parameter format) // PF (standard parameter format)
@ -32,45 +34,50 @@ TEST(ScsiCommandUtilTest, ModeSelect6)
buf[9] = 0x00; buf[9] = 0x00;
buf[10] = 0x02; buf[10] = 0x02;
buf[11] = 0x00; buf[11] = 0x00;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 256); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Requested sector size does not match current sector size"; << "Requested sector size does not match current sector size";
// Page 0 // Page 0
buf[12] = 0x00; buf[12] = 0x00;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Unsupported page 0 was not rejected"; << "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page) // Page 3 (Format Device Page)
buf[12] = 0x03; buf[12] = 0x03;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Requested sector size does not match current sector size"; << "Requested sector size does not match current sector size";
// Match the requested to the current sector size // Match the requested to the current sector size
buf[24] = 0x02; buf[24] = 0x02;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH - 1, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Not enough command parameters"; << "Not enough command parameters";
ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); ModeSelect(logger, scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512);
} }
TEST(ScsiCommandUtilTest, ModeSelect10) TEST(ScsiCommandUtilTest, ModeSelect10)
{ {
const int LENGTH = 30; const int LENGTH = 30;
DeviceLogger logger;
vector<int> cdb(10); vector<int> cdb(10);
vector<uint8_t> buf(LENGTH); vector<uint8_t> buf(LENGTH);
// PF (vendor-specific parameter format) must not fail but be ignored // PF (vendor-specific parameter format) must not fail but be ignored
cdb[1] = 0x00; cdb[1] = 0x00;
ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0); ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 0);
// PF (standard parameter format) // PF (standard parameter format)
cdb[1] = 0x10; cdb[1] = 0x10;
@ -78,33 +85,37 @@ TEST(ScsiCommandUtilTest, ModeSelect10)
buf[13] = 0x00; buf[13] = 0x00;
buf[14] = 0x02; buf[14] = 0x02;
buf[15] = 0x00; buf[15] = 0x00;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 256); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Requested sector size does not match current sector size"; << "Requested sector size does not match current sector size";
// Page 0 // Page 0
buf[16] = 0x00; buf[16] = 0x00;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Unsupported page 0 was not rejected"; << "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page) // Page 3 (Format Device Page)
buf[16] = 0x03; buf[16] = 0x03;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Requested sector size does not match current sector size"; << "Requested sector size does not match current sector size";
// Match the requested to the current sector size // Match the requested to the current sector size
buf[28] = 0x02; buf[28] = 0x02;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); }, Throws<scsi_exception>(AllOf( EXPECT_THAT([&] { ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH - 1, 512); },
Throws<scsi_exception>(AllOf(
Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST), Property(&scsi_exception::get_sense_key, sense_key::ILLEGAL_REQUEST),
Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST)))) Property(&scsi_exception::get_asc, asc::INVALID_FIELD_IN_PARAMETER_LIST))))
<< "Not enough command parameters"; << "Not enough command parameters";
ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512); ModeSelect(logger, scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512);
} }
TEST(ScsiCommandUtilTest, EnrichFormatPage) TEST(ScsiCommandUtilTest, EnrichFormatPage)

View File

@ -4,7 +4,7 @@ rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
.SH SYNOPSIS .SH SYNOPSIS
.B rascsi .B rascsi
[\fB\-F\fR \fIFOLDER\fR] [\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\-P\fR \fIACCESS_TOKEN_FILE\fR]
[\fB\-R\fR \fISCAN_DEPTH\fR] [\fB\-R\fR \fISCAN_DEPTH\fR]
[\fB\-h\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 .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'. 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 .TP
.BR \-L\fI " " \fILOG_LEVEL .BR \-L\fI " " \fILOG_LEVEL[:ID:[LUN]]
The rascsi log level (trace, debug, info, warn, err, off). The default log level is 'info'. 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 .TP
.BR \-P\fI " " \fIACCESS_TOKEN_FILE .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. 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.

View File

@ -6,7 +6,7 @@ NAME
rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins
SYNOPSIS 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 SCAN_DEPTH] [-h] [-n VENDOR:PRODUCT:REVISION] [-p PORT] [-r RE
SERVED_IDS] [-n TYPE] [-v] [-z LOCALE] [-IDn:[u] FILE] [-HDn[:u] SERVED_IDS] [-n TYPE] [-v] [-z LOCALE] [-IDn:[u] FILE] [-HDn[:u]
FILE]... FILE]...
@ -61,38 +61,39 @@ OPTIONS
absolute path needs to be specified. The initial default folder absolute path needs to be specified. The initial default folder
is '~/images'. is '~/images'.
-L LOG_LEVEL -L LOG_LEVEL[:ID:[LUN]]
The rascsi log level (trace, debug, info, warn, err, off). The 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 -P ACCESS_TOKEN_FILE
Enable authentication and read the access token from the speci Enable authentication and read the access token from the speci
fied file. The access token file must be owned by root and must fied file. The access token file must be owned by root and must
be readable by root only. be readable by root only.
-R SCAN_DEPTH -R SCAN_DEPTH
Scan for image files recursively, up to a depth of 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 Depth 0 means to ignore any folders within the default image
filder. Be careful when using this option with many sub-folders filder. Be careful when using this option with many sub-folders
in the default image folder. The default depth is 1. in the default image folder. The default depth is 1.
-h Show a help page. -h Show a help page.
-n VENDOR:PRODUCT:REVISION -n VENDOR:PRODUCT:REVISION
Set the vendor, product and revision for the device, to be re Set the vendor, product and revision for the device, to be re
turned with the INQUIRY data. A complete set of name components 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 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 VISION up to 4 characters. Padding with blanks to the maxium
length is automatically applied. Once set the name of a device length is automatically applied. Once set the name of a device
cannot be changed. cannot be changed.
-p PORT -p PORT
The rascsi server port, default is 6868. The rascsi server port, default is 6868.
-r RESERVED_IDS -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 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 SCLP, SCHS). If no type is specified for devices that support an
image file, rascsi tries to derive the type from the file exten image file, rascsi tries to derive the type from the file exten
sion. sion.
@ -100,20 +101,20 @@ OPTIONS
-v Display the rascsi version. -v Display the rascsi version.
-z LOCALE -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. The client can override the locale.
-IDn[:u] FILE -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. (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, For devices that do not support an image file (SCBR, SCDP, SCLP,
SCHS) the filename may have a special meaning or a dummy name SCHS) the filename may have a special meaning or a dummy name
can be provided. For SCBR and SCDP it is an optioinal priori can be provided. For SCBR and SCDP it is an optioinal priori
tized list of network interfaces, an optional IP address and tized list of network interfaces, an optional IP address and
netmask, e.g. "interfaces=eth0,eth1,wlan0:inet=10.10.20.1/24". 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". 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. 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 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 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: as ID 6:
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp daynaport rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp daynaport