Host services (SCHS) with realtime clock and shutdown, improved device inheritance (#647)

* Initial RTC skeleton

* Added device info

* Added TEST UNIT READY

* Fixed command dispatcher

* First untested naive implementation

* Comment update

* Code cleanup

* More code cleanup

* Updated date/time encoding

* Updated versioning

* Use standard RaSCSI INQUIRY version for SCRT device

* Manpage update

* Added shortcut for SCRT type

* Added support for rtc "filename"

* RTC supports LUNs > 0

* Fixed LUN count

* Renaming

* Renaming

* Manpage update

* Initial naive implementation

* SCRA is removable

* Updated command list

* Added controller field

* Shut down works, bus free phase is not yet entered

* Clear caches on shutdown

* Expose BusFree()

* Moved code

* Logging update

* Moved code

* Moved code

* Added comment

* Logging update

* Code cleanup

* Service device is not removable anymore (was only needed for testing)

* Manpage update

* Added comment

* Comment update

* Version update

* Renaming

* Comment update

* Comment update

* Renaming

* Fixed typo

* Added convenience method

* Property handling optimization

* Code cleanup

* Code cleanup

* Code cleanup, introduced base class

* Added TODO

* More code cleanup

* Removed unnecessary assignments

* Moved code

* Removed forward declaration

* Added base class

* INclude cleanup

* Moved scsi_command enum

* Fixed warnings

* Addressing circular dependencies

* Removed duplicate enum

* include file cleanup

* Include cleanup

* Reduced dependencies to Disk class (replaced by Device), fixed TODO

* Include cleanup

* PrimaryDevice implements ReportLuns

* Inheritance update

* Removed duplicate code

* Moved code to base class

* Cleanup

* Removed duplicate field

* Updated command dispatchign

* Comment update

* Moved code

* Updated method visibilities

* Moved MODE SENSE/MODE SELECT base code
This commit is contained in:
Uwe Seimet 2022-02-10 19:54:48 +01:00 committed by GitHub
parent 91cc0e836a
commit 5622694701
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 883 additions and 524 deletions

View File

@ -73,7 +73,7 @@ The rascsi server port, default is 6868.
.BR \-r\fI " " \fIRESERVED_IDS
Comma-separated list of IDs to reserve.
.BR \-p\fI " " \fITYPE
The optional case-insensitive device type (SAHD, SCHD, SCRM, SCCD, SCMO, SCBR, SCDP). If no type is specified for devices that support an image file, rascsi tries to derive the type from the file extension.
The optional case-insensitive device type (SAHD, SCHD, SCRM, SCCD, SCMO, SCBR, SCDP, SCHS). If no type is specified for devices that support an image file, rascsi tries to derive the type from the file extension.
.TP
.BR \-v\fI " " \fI
Display the rascsi version.
@ -84,7 +84,7 @@ Overrides the default locale for client-faces error messages. The client can ove
.BR \-ID\fIn[:u] " " \fIFILE
n is the SCSI ID number (0-7). u (0-31) is the optional LUN (logical unit). The default LUN is 0.
.IP
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) a dummy name must be provided.
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, SCHS) a dummy name must be provided.
.TP
.BR \-HD\fIn[:u] " " \fIFILE
n is the SASI ID number (0-15). The effective SASI ID is calculated as n/2, the effective SASI LUN is calculated is the remainder of n/2. Alternatively the n:u syntax can be used, where ns is the SASI ID (0-7) and u the LUN (0-1).
@ -101,7 +101,7 @@ Launch RaSCSI with an Apple hard drive image as ID 0 and a CD-ROM as ID 2
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 device file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter as ID 6:
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp daynaport
To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800

View File

@ -93,9 +93,9 @@ OPTIONS
-r RESERVED_IDS
Comma-separated list of IDs to reserve. -p TYPE The optional
case-insensitive device type (SAHD, SCHD, SCRM, SCCD, SCMO,
SCBR, SCDP). If no type is specified for devices that support an
image file, rascsi tries to derive the type from the file exten
sion.
SCBR, SCDP, SCHS). If no type is specified for devices that sup
port an image file, rascsi tries to derive the type from the
file extension.
-v Display the rascsi version.
@ -108,8 +108,8 @@ OPTIONS
(logical unit). The default LUN is 0.
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) a
dummy name must be provided.
For devices that do not support an image file (SCBR, SCDP, SCHS)
a dummy name must be provided.
-HDn[:u] FILE
n is the SASI ID number (0-15). The effective SASI ID is calcu
@ -133,7 +133,7 @@ EXAMPLES
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
as ID 6:
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp daynaport
To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800

View File

@ -148,7 +148,8 @@ Specifies the device type. This type overrides the type derived from the file ex
cd: CD-ROM
mo: Magneto-Optical disk
bridge: Bridge device (Only applicable to the Sharp X68000)
daynaport: DaynaPORT network adapter
daynaport: DaynaPort network adapter
services: Host services device
.TP
.BR \-n\fI " " \fIVENDOR:PRODUCT:REVISION
The vendor, product and revision for the device, to be returned with the INQUIRY data. A complete set of name components must be provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up to 4 characters. Padding with blanks to the maxium length is automatically applied. Once set the name of a device cannot be changed.

View File

@ -128,7 +128,8 @@ OPTIONS
cd: CD-ROM
mo: Magneto-Optical disk
bridge: Bridge device (Only applicable to the Sharp X68000)
daynaport: DaynaPORT network adapter
daynaport: DaynaPort network adapter
services: Host services device
-n VENDOR:PRODUCT:REVISION
The vendor, product and revision for the device, to be returned

View File

@ -115,7 +115,7 @@ void SASIDEV::Connect(int id, BUS *bus)
// Set the logical unit
//
//---------------------------------------------------------------------------
void SASIDEV::SetUnit(int no, Disk *dev)
void SASIDEV::SetUnit(int no, Device *dev)
{
ASSERT(no < UnitMax);
@ -665,7 +665,7 @@ void SASIDEV::CmdTestUnitReady()
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->TestUnitReady(this);
((Disk *)ctrl.device)->TestUnitReady(this);
}
//---------------------------------------------------------------------------
@ -678,7 +678,7 @@ void SASIDEV::CmdRezero()
LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->Rezero(this);
((Disk *)ctrl.device)->Rezero(this);
}
//---------------------------------------------------------------------------
@ -691,7 +691,7 @@ void SASIDEV::CmdRequestSense()
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->RequestSense(this);
((Disk *)ctrl.device)->RequestSense(this);
}
//---------------------------------------------------------------------------
@ -704,7 +704,7 @@ void SASIDEV::CmdFormat()
LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->FormatUnit(this);
((Disk *)ctrl.device)->FormatUnit(this);
}
//---------------------------------------------------------------------------
@ -717,7 +717,7 @@ void SASIDEV::CmdReassignBlocks()
LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->ReassignBlocks(this);
((Disk *)ctrl.device)->ReassignBlocks(this);
}
//---------------------------------------------------------------------------
@ -777,7 +777,7 @@ void SASIDEV::CmdRead6()
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Command processing on drive
ctrl.length = ctrl.device->Read(ctrl.cmd, ctrl.buffer, record);
ctrl.length = ((Disk *)ctrl.device)->Read(ctrl.cmd, ctrl.buffer, record);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
@ -812,7 +812,7 @@ void SASIDEV::CmdWrite6()
LOGTRACE("%s WRITE(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
// Command processing on drive
ctrl.length = ctrl.device->WriteCheck(record);
ctrl.length = ((Disk *)ctrl.device)->WriteCheck(record);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
@ -836,7 +836,7 @@ void SASIDEV::CmdSeek6()
LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__);
// Command processing on drive
ctrl.device->Seek6(this);
((Disk *)ctrl.device)->Seek6(this);
}
//---------------------------------------------------------------------------
@ -849,7 +849,7 @@ void SASIDEV::CmdAssign()
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
// Command processing on drive
bool status = ctrl.device->CheckReady();
bool status = ((Disk *)ctrl.device)->CheckReady();
if (!status) {
// Failure (Error)
Error();
@ -873,7 +873,7 @@ void SASIDEV::CmdSpecify()
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
// Command processing on drive
bool status = ctrl.device->CheckReady();
bool status = ((Disk *)ctrl.device)->CheckReady();
if (!status) {
// Failure (Error)
Error();
@ -1086,7 +1086,7 @@ bool SASIDEV::XferIn(BYTE *buf)
case eCmdRead10:
case eCmdRead16:
// Read from disk
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, buf, ctrl.next);
ctrl.length = ((Disk *)ctrl.unit[lun])->Read(ctrl.cmd, buf, ctrl.next);
ctrl.next++;
// If there is an error, go to the status phase
@ -1124,7 +1124,7 @@ bool SASIDEV::XferOut(bool cont)
if (!ctrl.unit[lun]) {
return false;
}
Disk *device = ctrl.unit[lun];
Disk *device = (Disk *)ctrl.unit[lun];
switch (ctrl.cmd[0]) {
case SASIDEV::eCmdModeSelect6:
@ -1220,7 +1220,8 @@ void SASIDEV::FlushUnit()
if (!ctrl.unit[lun]) {
return;
}
Disk *device = ctrl.unit[lun];
Disk *disk = (Disk *)ctrl.unit[lun];
// WRITE system only
switch ((SASIDEV::sasi_command)ctrl.cmd[0]) {
@ -1248,7 +1249,7 @@ void SASIDEV::FlushUnit()
LOGWARN(" Reserved: %02X\n",(WORD)ctrl.cmd[5]);
LOGWARN(" Ctrl Len: %08X\n",(WORD)ctrl.length);
if (!device->ModeSelect(
if (!disk->ModeSelect(
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
// MODE SELECT failed
LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]);

View File

@ -21,6 +21,7 @@
#include "fileio.h"
#include "log.h"
class Device;
//===========================================================================
//
@ -123,10 +124,10 @@ public:
DWORD length; // Transfer remaining length
// Logical unit
Disk *unit[UnitMax];
Device *unit[UnitMax];
// The current device
Disk *device;
Device *device;
// The LUN from the IDENTIFY message
int lun;
@ -143,8 +144,8 @@ public:
// Connect
void Connect(int id, BUS *sbus); // Controller connection
Disk* GetUnit(int no); // Get logical unit
void SetUnit(int no, Disk *dev); // Logical unit setting
Device* GetUnit(int no); // Get logical unit
void SetUnit(int no, Device *dev); // Logical unit setting
bool HasUnit(); // Has a valid logical unit
// Other

View File

@ -27,6 +27,8 @@
SCSIDEV::SCSIDEV() : SASIDEV()
{
shutdown_mode = NONE;
// Synchronous transfer work initialization
scsi.syncenable = FALSE;
scsi.syncperiod = 50;
@ -153,6 +155,22 @@ void SCSIDEV::BusFree()
ctrl.lun = -1;
// When the bus is free RaSCSI or the Pi may be shut down
switch(shutdown_mode) {
case RASCSI:
LOGINFO("RaSCSI shutdown requested");
exit(0);
break;
case PI:
LOGINFO("Raspberry Pi shutdown requested");
system("init 0");
break;
default:
break;
}
return;
}
@ -221,7 +239,7 @@ void SCSIDEV::Execute()
ctrl.execstart = SysTimer::GetTimerLow();
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((SCSIDEV::scsi_command)ctrl.cmd[0] != eCmdRequestSense) {
if ((ScsiDefs::scsi_command)ctrl.cmd[0] != ScsiDefs::eCmdRequestSense) {
ctrl.status = 0;
}
@ -229,7 +247,8 @@ void SCSIDEV::Execute()
int lun = GetEffectiveLun();
if (!ctrl.unit[lun]) {
if ((SCSIDEV::scsi_command)ctrl.cmd[0] != eCmdInquiry && (SCSIDEV::scsi_command)ctrl.cmd[0] != eCmdRequestSense) {
if ((ScsiDefs::scsi_command)ctrl.cmd[0] != ScsiDefs::eCmdInquiry &&
(ScsiDefs::scsi_command)ctrl.cmd[0] != ScsiDefs::eCmdRequestSense) {
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetSCSIID());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
@ -247,7 +266,7 @@ void SCSIDEV::Execute()
ctrl.device = ctrl.unit[lun];
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((SCSIDEV::scsi_command)ctrl.cmd[0] != eCmdRequestSense) {
if ((ScsiDefs::scsi_command)ctrl.cmd[0] != ScsiDefs::eCmdRequestSense) {
ctrl.device->SetStatusCode(0);
}
@ -258,10 +277,10 @@ void SCSIDEV::Execute()
}
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if ((SCSIDEV::scsi_command)ctrl.cmd[0] == eCmdInquiry && !ctrl.unit[lun]) {
if ((ScsiDefs::scsi_command)ctrl.cmd[0] == ScsiDefs::eCmdInquiry && !ctrl.unit[lun]) {
lun = GetEffectiveLun();
LOGDEBUG("Reporting LUN %d for device ID %d as not supported", lun, ctrl.device->GetId());
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, ctrl.device->GetId());
ctrl.buffer[0] = 0x7f;
}

View File

@ -25,51 +25,12 @@
//===========================================================================
class SCSIDEV : public SASIDEV
{
public:
enum scsi_command : int {
eCmdTestUnitReady = 0x00,
eCmdRezero = 0x01,
eCmdRequestSense = 0x03,
eCmdFormat = 0x04,
eCmdReassign = 0x07,
eCmdRead6 = 0x08,
eCmdRetrieveStats = 0x09, // DaynaPort specific command
eCmdWrite6 = 0x0A,
eCmdSeek6 = 0x0B,
eCmdSetIfaceMode = 0x0C, // DaynaPort specific command
eCmdSetMcastAddr = 0x0D, // DaynaPort specific command
eCmdEnableInterface = 0x0E, // DaynaPort specific command
eCmdInquiry = 0x12,
eCmdModeSelect6 = 0x15,
eCmdReserve6 = 0x16,
eCmdRelease6 = 0x17,
eCmdModeSense6 = 0x1A,
eCmdStartStop = 0x1B,
eCmdSendDiag = 0x1D,
eCmdRemoval = 0x1E,
eCmdReadCapacity10 = 0x25,
eCmdRead10 = 0x28,
eCmdWrite10 = 0x2A,
eCmdSeek10 = 0x2B,
eCmdVerify10 = 0x2F,
eCmdSynchronizeCache10 = 0x35,
eCmdReadDefectData10 = 0x37,
eCmdReadLong10 = 0x3E,
eCmdWriteLong10 = 0x3F,
eCmdReadToc = 0x43,
eCmdGetEventStatusNotification = 0x4A,
eCmdModeSelect10 = 0x55,
eCmdReserve10 = 0x56,
eCmdRelease10 = 0x57,
eCmdModeSense10 = 0x5A,
eCmdRead16 = 0x88,
eCmdWrite16 = 0x8A,
eCmdVerify16 = 0x8F,
eCmdSynchronizeCache16 = 0x91,
eCmdReadCapacity16_ReadLong16 = 0x9E,
eCmdWriteLong16 = 0x9F,
eCmdReportLuns = 0xA0
enum rascsi_shutdown_mode {
NONE,
RASCSI,
PI
};
// Internal data definition
@ -86,7 +47,6 @@ public:
BYTE msb[256];
} scsi_t;
public:
// Basic Functions
SCSIDEV();
~SCSIDEV();
@ -103,6 +63,8 @@ public:
void Error(ERROR_CODES::sense_key sense_key = ERROR_CODES::sense_key::NO_SENSE,
ERROR_CODES::asc asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION) override; // Common error handling
void ShutDown(rascsi_shutdown_mode shutdown_mode) { this->shutdown_mode = shutdown_mode; }
private:
// Phase
@ -122,5 +84,7 @@ private:
bool XferMsg(DWORD msg);
scsi_t scsi; // Internal data
rascsi_shutdown_mode shutdown_mode;
};

View File

@ -22,7 +22,6 @@
#include "log.h"
#include "filepath.h"
#include "cfilesystem.h"
#include "../rascsi.h"
//---------------------------------------------------------------------------
//

View File

@ -22,7 +22,6 @@
#endif
#include <zlib.h> // For crc32()
#include "os.h"
#include "../rascsi.h"
#include "ctapdriver.h"
#include "log.h"
#include "exceptions.h"

View File

@ -29,7 +29,7 @@ Device::Device(const string& type)
ready = false;
reset = false;
attn = false;
supported_luns = 1;
supported_luns = 32;
protectable = false;
write_protected = false;
read_only = false;

View File

@ -162,6 +162,7 @@ public:
const string GetPaddedName() const;
bool SupportsParams() const { return supports_params; }
bool SupportsFile() const { return !supports_params; }
void SupportsParams(bool supports_paams) { this->supports_params = supports_paams; }
const map<string, string> GetParams() const { return params; }
const string GetParam(const string&);

View File

@ -19,6 +19,7 @@
#include <ifaddrs.h>
#include <set>
#include <map>
#include "host_services.h"
using namespace std;
using namespace rascsi_interface;
@ -31,8 +32,6 @@ DeviceFactory::DeviceFactory()
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
// Some old Sun CD-ROM drives support 512 bytes per sector
sector_sizes[SCCD] = { 512, 2048};
sector_sizes[SCBR] = {};
sector_sizes[SCDP] = {};
// 128 MB, 512 bytes per sector, 248826 sectors
geometries[SCMO][0x797f400] = make_pair(512, 248826);
@ -42,12 +41,6 @@ DeviceFactory::DeviceFactory()
geometries[SCMO][0x1fc8b800] = make_pair(512, 1041500);
// 640 MB, 20248 bytes per sector, 310352 sectors
geometries[SCMO][0x25e28000] = make_pair(2048, 310352);
geometries[SAHD] = {};
geometries[SCHD] = {};
geometries[SCRM] = {};
geometries[SCCD] = {};
geometries[SCBR] = {};
geometries[SCDP] = {};
string network_interfaces;
for (const auto& network_interface : GetNetworkInterfaces()) {
@ -57,11 +50,6 @@ DeviceFactory::DeviceFactory()
network_interfaces += network_interface;
}
default_params[SAHD] = {};
default_params[SCHD] = {};
default_params[SCRM] = {};
default_params[SCMO] = {};
default_params[SCCD] = {};
default_params[SCBR]["interfaces"] = network_interfaces;
default_params[SCDP]["interfaces"] = network_interfaces;
@ -107,6 +95,9 @@ PbDeviceType DeviceFactory::GetTypeForFile(const string& filename)
else if (filename == "daynaport") {
return SCDP;
}
else if (filename == "services") {
return SCHS;
}
return UNDEFINED;
}
@ -146,7 +137,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
device->SetProduct("FIREBALL");
}
}
device->SetSupportedLuns(32);
device->SetProtectable(true);
device->SetStoppable(true);
break;
@ -154,7 +144,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
case SCRM:
device = new SCSIHD(true);
device->SetSupportedLuns(32);
device->SetProtectable(true);
device->SetStoppable(true);
device->SetRemovable(true);
@ -165,7 +154,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
case SCMO:
device = new SCSIMO();
device->SetSupportedLuns(32);
device->SetProtectable(true);
device->SetStoppable(true);
device->SetRemovable(true);
@ -177,7 +165,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
case SCCD:
device = new SCSICD();
device->SetSupportedLuns(32);
device->SetReadOnly(true);
device->SetStoppable(true);
device->SetRemovable(true);
@ -188,7 +175,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
case SCBR:
device = new SCSIBR();
device->SetSupportedLuns(32);
device->SetProduct("SCSI HOST BRIDGE");
device->SupportsParams(true);
device->SetDefaultParams(default_params[SCBR]);
@ -196,7 +182,6 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
case SCDP:
device = new SCSIDaynaPort();
device->SetSupportedLuns(32);
// Since this is an emulation for a specific device the full INQUIRY data have to be set accordingly
device->SetVendor("Dayna");
device->SetProduct("SCSI/Link");
@ -205,6 +190,13 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
device->SetDefaultParams(default_params[SCDP]);
break;
case SCHS:
device = new HostServices();
// Since this is an emulation for a specific device the full INQUIRY data have to be set accordingly
device->SetVendor("RaSCSI");
device->SetProduct("Host Services");
break;
default:
break;
}

View File

@ -16,15 +16,16 @@
//---------------------------------------------------------------------------
#include "os.h"
#include "controllers/sasidev_ctrl.h"
#include "device_factory.h"
#include "exceptions.h"
#include "disk.h"
#include "mode_page_device.h"
#include <sstream>
#include "../rascsi.h"
Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockCommands()
Disk::Disk(const std::string id) : ModePageDevice(id), ScsiBlockCommands()
{
disks.insert(this);
// Work initialization
configured_sector_size = 0;
disk.size = 0;
@ -32,42 +33,34 @@ Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockC
disk.dcache = NULL;
disk.image_offset = 0;
AddCommand(SCSIDEV::eCmdTestUnitReady, "TestUnitReady", &Disk::TestUnitReady);
AddCommand(SCSIDEV::eCmdRezero, "Rezero", &Disk::Rezero);
AddCommand(SCSIDEV::eCmdRequestSense, "RequestSense", &Disk::RequestSense);
AddCommand(SCSIDEV::eCmdFormat, "FormatUnit", &Disk::FormatUnit);
AddCommand(SCSIDEV::eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
AddCommand(SCSIDEV::eCmdRead6, "Read6", &Disk::Read6);
AddCommand(SCSIDEV::eCmdWrite6, "Write6", &Disk::Write6);
AddCommand(SCSIDEV::eCmdSeek6, "Seek6", &Disk::Seek6);
AddCommand(SCSIDEV::eCmdInquiry, "Inquiry", &Disk::Inquiry);
AddCommand(SCSIDEV::eCmdModeSelect6, "ModeSelect6", &Disk::ModeSelect6);
AddCommand(SCSIDEV::eCmdReserve6, "Reserve6", &Disk::Reserve6);
AddCommand(SCSIDEV::eCmdRelease6, "Release6", &Disk::Release6);
AddCommand(SCSIDEV::eCmdModeSense6, "ModeSense6", &Disk::ModeSense6);
AddCommand(SCSIDEV::eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
AddCommand(SCSIDEV::eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
AddCommand(SCSIDEV::eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
AddCommand(SCSIDEV::eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
AddCommand(SCSIDEV::eCmdRead10, "Read10", &Disk::Read10);
AddCommand(SCSIDEV::eCmdWrite10, "Write10", &Disk::Write10);
AddCommand(SCSIDEV::eCmdReadLong10, "ReadLong10", &Disk::ReadLong10);
AddCommand(SCSIDEV::eCmdWriteLong10, "WriteLong10", &Disk::WriteLong10);
AddCommand(SCSIDEV::eCmdWriteLong16, "WriteLong16", &Disk::WriteLong16);
AddCommand(SCSIDEV::eCmdSeek10, "Seek10", &Disk::Seek10);
AddCommand(SCSIDEV::eCmdVerify10, "Verify10", &Disk::Verify10);
AddCommand(SCSIDEV::eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
AddCommand(SCSIDEV::eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
AddCommand(SCSIDEV::eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
AddCommand(SCSIDEV::eCmdModeSelect10, "ModeSelect10", &Disk::ModeSelect10);
AddCommand(SCSIDEV::eCmdReserve10, "Reserve10", &Disk::Reserve10);
AddCommand(SCSIDEV::eCmdRelease10, "Release10", &Disk::Release10);
AddCommand(SCSIDEV::eCmdModeSense10, "ModeSense10", &Disk::ModeSense10);
AddCommand(SCSIDEV::eCmdRead16, "Read16", &Disk::Read16);
AddCommand(SCSIDEV::eCmdWrite16, "Write16", &Disk::Write16);
AddCommand(SCSIDEV::eCmdVerify16, "Verify16", &Disk::Verify16);
AddCommand(SCSIDEV::eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
AddCommand(SCSIDEV::eCmdReportLuns, "ReportLuns", &Disk::ReportLuns);
AddCommand(ScsiDefs::eCmdRezero, "Rezero", &Disk::Rezero);
AddCommand(ScsiDefs::eCmdFormat, "FormatUnit", &Disk::FormatUnit);
AddCommand(ScsiDefs::eCmdReassign, "ReassignBlocks", &Disk::ReassignBlocks);
AddCommand(ScsiDefs::eCmdRead6, "Read6", &Disk::Read6);
AddCommand(ScsiDefs::eCmdWrite6, "Write6", &Disk::Write6);
AddCommand(ScsiDefs::eCmdSeek6, "Seek6", &Disk::Seek6);
AddCommand(ScsiDefs::eCmdReserve6, "Reserve6", &Disk::Reserve6);
AddCommand(ScsiDefs::eCmdRelease6, "Release6", &Disk::Release6);
AddCommand(ScsiDefs::eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
AddCommand(ScsiDefs::eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
AddCommand(ScsiDefs::eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
AddCommand(ScsiDefs::eCmdReadCapacity10, "ReadCapacity10", &Disk::ReadCapacity10);
AddCommand(ScsiDefs::eCmdRead10, "Read10", &Disk::Read10);
AddCommand(ScsiDefs::eCmdWrite10, "Write10", &Disk::Write10);
AddCommand(ScsiDefs::eCmdReadLong10, "ReadLong10", &Disk::ReadLong10);
AddCommand(ScsiDefs::eCmdWriteLong10, "WriteLong10", &Disk::WriteLong10);
AddCommand(ScsiDefs::eCmdWriteLong16, "WriteLong16", &Disk::WriteLong16);
AddCommand(ScsiDefs::eCmdSeek10, "Seek10", &Disk::Seek10);
AddCommand(ScsiDefs::eCmdVerify10, "Verify10", &Disk::Verify10);
AddCommand(ScsiDefs::eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
AddCommand(ScsiDefs::eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
AddCommand(ScsiDefs::eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
AddCommand(ScsiDefs::eCmdReserve10, "Reserve10", &Disk::Reserve10);
AddCommand(ScsiDefs::eCmdRelease10, "Release10", &Disk::Release10);
AddCommand(ScsiDefs::eCmdRead16, "Read16", &Disk::Read16);
AddCommand(ScsiDefs::eCmdWrite16, "Write16", &Disk::Write16);
AddCommand(ScsiDefs::eCmdVerify16, "Verify16", &Disk::Verify16);
AddCommand(ScsiDefs::eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
}
Disk::~Disk()
@ -89,9 +82,11 @@ Disk::~Disk()
for (auto const& command : commands) {
delete command.second;
}
disks.erase(this);
}
void Disk::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (Disk::*execute)(SASIDEV *))
void Disk::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (Disk::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
@ -100,8 +95,8 @@ bool Disk::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0])];
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);
@ -110,8 +105,10 @@ bool Disk::Dispatch(SCSIDEV *controller)
return true;
}
// Unknown command
return false;
LOGTRACE("%s Calling base class for dispatching $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->cmd[0]);
// The base class handles the less specific commands
return ModePageDevice::Dispatch(controller);
}
//---------------------------------------------------------------------------
@ -147,16 +144,6 @@ void Disk::Open(const Filepath& path)
SetLocked(false);
}
void Disk::TestUnitReady(SASIDEV *controller)
{
if (!CheckReady()) {
controller->Error();
return;
}
controller->Status();
}
void Disk::Rezero(SASIDEV *controller)
{
if (!CheckReady()) {
@ -167,28 +154,6 @@ void Disk::Rezero(SASIDEV *controller)
controller->Status();
}
void Disk::RequestSense(SASIDEV *controller)
{
int lun = controller->GetEffectiveLun();
// Note: According to the SCSI specs the LUN handling for REQUEST SENSE non-existing LUNs do *not* result
// in CHECK CONDITION. Only the Sense Key and ASC are set in order to signal the non-existing LUN.
if (!ctrl->unit[lun]) {
// LUN 0 can be assumed to be present (required to call RequestSense() below)
lun = 0;
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
ctrl->status = 0x00;
}
ctrl->length = ctrl->unit[lun]->RequestSense(ctrl->cmd, ctrl->buffer);
ASSERT(ctrl->length > 0);
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
controller->DataIn();
}
void Disk::FormatUnit(SASIDEV *controller)
{
if (!Format(ctrl->cmd)) {
@ -392,93 +357,6 @@ void Disk::Verify16(SASIDEV *controller)
}
}
void Disk::Inquiry(SASIDEV *controller)
{
int lun = controller->GetEffectiveLun();
const ScsiPrimaryCommands *device = ctrl->unit[lun];
// Find a valid unit
// TODO The code below is probably wrong. It results in the same INQUIRY data being
// used for all LUNs, even though each LUN has its individual set of INQUIRY data.
// In addition, it supports gaps in the LUN list, which is not correct.
if (!device) {
for (int valid_lun = 0; valid_lun < SASIDEV::UnitMax; valid_lun++) {
if (ctrl->unit[valid_lun]) {
device = ctrl->unit[valid_lun];
break;
}
}
}
if (device) {
ctrl->length = Inquiry(ctrl->cmd, ctrl->buffer);
} else {
ctrl->length = 0;
}
if (ctrl->length <= 0) {
controller->Error();
return;
}
// Report if the device does not support the requested LUN
if (!ctrl->unit[lun]) {
LOGDEBUG("Reporting LUN %d for device ID %d as not supported", lun, ctrl->device->GetId());
ctrl->buffer[0] |= 0x7f;
}
controller->DataIn();
}
void Disk::ModeSelect6(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck6(ctrl->cmd);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataOut();
}
void Disk::ModeSelect10(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck10(ctrl->cmd);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataOut();
}
void Disk::ModeSense6(SASIDEV *controller)
{
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataIn();
}
void Disk::ModeSense10(SASIDEV *controller)
{
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataIn();
}
void Disk::StartStopUnit(SASIDEV *controller)
{
if (!StartStop(ctrl->cmd)) {
@ -558,122 +436,6 @@ bool Disk::Eject(bool force)
return status;
}
bool Disk::CheckReady()
{
// Not ready if reset
if (IsReset()) {
SetStatusCode(STATUS_DEVRESET);
SetReset(false);
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
return false;
}
// Not ready if it needs attention
if (IsAttn()) {
SetStatusCode(STATUS_ATTENTION);
SetAttn(false);
LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__);
return false;
}
// Return status if not ready
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
LOGTRACE("%s Disk not ready", __PRETTY_FUNCTION__);
return false;
}
// Initialization with no error
LOGTRACE("%s Disk is ready", __PRETTY_FUNCTION__);
return true;
}
//---------------------------------------------------------------------------
//
// REQUEST SENSE
// *SASI is a separate process
//
//---------------------------------------------------------------------------
int Disk::RequestSense(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// Return not ready only if there are no errors
if (GetStatusCode() == STATUS_NOERROR) {
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
}
}
// Size determination (according to allocation length)
int size = (int)cdb[4];
ASSERT((size >= 0) && (size < 0x100));
// For SCSI-1, transfer 4 bytes when the size is 0
// (Deleted this specification for SCSI-2)
if (size == 0) {
size = 4;
}
// Clear the buffer
memset(buf, 0, size);
// Set 18 bytes including extended sense data
// Current error
buf[0] = 0x70;
buf[2] = (BYTE)(GetStatusCode() >> 16);
buf[7] = 10;
buf[12] = (BYTE)(GetStatusCode() >> 8);
buf[13] = (BYTE)GetStatusCode();
return size;
}
int Disk::ModeSelectCheck(const DWORD *cdb, int length)
{
// Error if save parameters are set for other types than of SCHD or SCRM
if (!IsSCSIHD() && (cdb[1] & 0x01)) {
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
return length;
}
int Disk::ModeSelectCheck6(const DWORD *cdb)
{
// Receive the data specified by the parameter length
return ModeSelectCheck(cdb, cdb[4]);
}
int Disk::ModeSelectCheck10(const DWORD *cdb)
{
// Receive the data specified by the parameter length
int length = cdb[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
}
return ModeSelectCheck(cdb, length);
}
bool Disk::ModeSelect(const DWORD* /*cdb*/, const BYTE *buf, int length)
{
ASSERT(buf);
ASSERT(length >= 0);
// cannot be set
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
int Disk::ModeSense6(const DWORD *cdb, BYTE *buf)
{
// Get length, clear buffer
@ -1425,38 +1187,6 @@ void Disk::ReadCapacity16_ReadLong16(SASIDEV *controller)
}
}
void Disk::ReportLuns(SASIDEV *controller)
{
BYTE *buf = ctrl->buffer;
if (!CheckReady()) {
controller->Error();
return;
}
int allocation_length = (ctrl->cmd[6] << 24) + (ctrl->cmd[7] << 16) + (ctrl->cmd[8] << 8) + ctrl->cmd[9];
memset(buf, 0, allocation_length);
// Count number of available LUNs for the current device
int luns;
for (luns = 0; luns < controller->GetCtrl()->device->GetSupportedLuns(); luns++) {
if (!controller->GetCtrl()->unit[luns]) {
break;
}
}
// LUN list length, 8 bytes per LUN
// SCSI standard: The contents of the LUN LIST LENGTH field are not altered based on the allocation length
buf[0] = (luns * 8) >> 24;
buf[1] = (luns * 8) >> 16;
buf[2] = (luns * 8) >> 8;
buf[3] = luns * 8;
ctrl->length = allocation_length < 8 + luns * 8 ? allocation_length : 8 + luns * 8;
controller->DataIn();
}
//---------------------------------------------------------------------------
//
// RESERVE(6)

View File

@ -25,15 +25,14 @@
#include "disk_track_cache.h"
#include "file_support.h"
#include "filepath.h"
#include "interfaces/scsi_block_commands.h"
#include "interfaces/scsi_primary_commands.h"
#include "mode_page_device.h"
#include <string>
#include <set>
#include <map>
#include "../rascsi.h"
#include "interfaces/scsi_block_commands.h"
#include "interfaces/scsi_primary_commands.h"
class Disk : public Device, ScsiPrimaryCommands, ScsiBlockCommands
class Disk : public ModePageDevice, ScsiBlockCommands
{
private:
enum access_mode { RW6, RW10, RW16 };
@ -45,8 +44,6 @@ private:
// The mapping of supported capacities to block sizes and block counts, empty if there is no capacity restriction
map<uint64_t, Geometry> geometries;
SASIDEV::ctrl_t *ctrl;
typedef struct {
uint32_t size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
// TODO blocks should be a 64 bit value in order to support higher capacities
@ -61,9 +58,9 @@ private:
_command_t(const char* _name, void (Disk::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<SCSIDEV::scsi_command, command_t*> commands;
std::map<ScsiDefs::scsi_command, command_t*> commands;
void AddCommand(SCSIDEV::scsi_command, const char*, void (Disk::*)(SASIDEV *));
void AddCommand(ScsiDefs::scsi_command, const char*, void (Disk::*)(SASIDEV *));
public:
Disk(std::string);
@ -78,17 +75,9 @@ public:
void GetPath(Filepath& path) const;
bool Eject(bool) override;
private:
// Commands covered by the SCSI specification (see https://www.t10.org/drafts.htm)
virtual void TestUnitReady(SASIDEV *) override;
void Inquiry(SASIDEV *) override;
void RequestSense(SASIDEV *) override;
void ModeSelect6(SASIDEV *) override;
void ModeSelect10(SASIDEV *) override;
void ModeSense6(SASIDEV *) override;
void ModeSense10(SASIDEV *) override;
void Rezero(SASIDEV *);
void FormatUnit(SASIDEV *) override;
void ReassignBlocks(SASIDEV *) override;
void StartStopUnit(SASIDEV *) override;
void SendDiagnostic(SASIDEV *) override;
void PreventAllowMediumRemoval(SASIDEV *);
@ -108,16 +97,22 @@ public:
void Verify10(SASIDEV *) override;
void Verify16(SASIDEV *) override;
void Seek(SASIDEV *);
void Seek6(SASIDEV *);
void Seek10(SASIDEV *);
void ReadCapacity10(SASIDEV *) override;
void ReadCapacity16(SASIDEV *) override;
void ReportLuns(SASIDEV *) override;
void Reserve6(SASIDEV *);
void Reserve10(SASIDEV *);
void Release6(SASIDEV *);
void Release10(SASIDEV *);
public:
// Commands covered by the SCSI specification (see https://www.t10.org/drafts.htm)
void Rezero(SASIDEV *);
void FormatUnit(SASIDEV *) override;
void ReassignBlocks(SASIDEV *) override;
void Seek6(SASIDEV *);
// Command helpers
virtual int Inquiry(const DWORD *cdb, BYTE *buf) = 0; // INQUIRY command
virtual int WriteCheck(DWORD block); // WRITE check
@ -143,12 +138,10 @@ public:
void SetBlockCount(uint32_t);
bool CheckBlockAddress(SASIDEV *, access_mode);
bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode);
bool CheckReady();
// TODO This method should not be called by SASIDEV
virtual bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length);
protected:
int ModeSense6(const DWORD *cdb, BYTE *buf);
int ModeSense10(const DWORD *cdb, BYTE *buf);
virtual int AddErrorPage(bool change, BYTE *buf);
virtual int AddFormatPage(bool change, BYTE *buf);
virtual int AddDrivePage(bool change, BYTE *buf);
@ -158,11 +151,11 @@ protected:
int AddCDROMPage(bool change, BYTE *buf);
int AddCDDAPage(bool, BYTE *buf);
virtual int RequestSense(const DWORD *cdb, BYTE *buf);
// Internal disk data
disk_t disk;
set<Disk *> disks;
private:
void Read(SASIDEV *, uint64_t);
void Write(SASIDEV *, uint64_t);
@ -171,9 +164,4 @@ private:
void ReadWriteLong16(SASIDEV *);
void ReadCapacity16_ReadLong16(SASIDEV *);
bool Format(const DWORD *cdb);
int ModeSense6(const DWORD *cdb, BYTE *buf);
int ModeSense10(const DWORD *cdb, BYTE *buf);
int ModeSelectCheck(const DWORD *cdb, int length);
int ModeSelectCheck6(const DWORD *cdb);
int ModeSelectCheck10(const DWORD *cdb);
};

View File

@ -17,7 +17,6 @@
#pragma once
#include "../rascsi.h"
#include "filepath.h"
// Number of tracks to cache

View File

@ -0,0 +1,134 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
//
// Features of the host services device:
//
// 1. Vendor-specific mode page 0x20 returns the current date and time (realtime clock)
//
// typedef struct {
// // Major and minor version of this data structure
// uint8_t major_version;
// uint8_t minor_version;
// // Current date and time, with daylight savings time adjustment applied
// uint8_t year; // year - 1900
// uint8_t month; // 0-11
// uint8_t day; // 1-31
// uint8_t hour; // 0-23
// uint8_t minute; // 0-59
// uint8_t second; // 0-59
// } mode_page_datetime;
//
// 2. STOP UNIT shuts down RaSCSI or the Raspberry Pi
// a) !start && !load (STOP): Shut down RaSCSI
// b) !start && load (EJECT): Shut down the Raspberry Pi
//
#include "host_services.h"
bool HostServices::Dispatch(SCSIDEV *controller)
{
unsigned int cmd = controller->GetCtrl()->cmd[0];
// Only certain commands are supported
// TODO Do not inherit from Disk, mode page handling should be moved to ModePageDevice
if (cmd == ScsiDefs::eCmdTestUnitReady || cmd == ScsiDefs::eCmdRequestSense
|| cmd == ScsiDefs::eCmdInquiry || cmd == ScsiDefs::eCmdReportLuns
|| cmd == ScsiDefs::eCmdModeSense6 || cmd == ScsiDefs::eCmdModeSense10
|| cmd == ScsiDefs::eCmdStartStop) {
LOGTRACE("%s Calling base class for dispatching $%02X", __PRETTY_FUNCTION__, cmd);
return Disk::Dispatch(controller);
}
return false;
}
void HostServices::TestUnitReady(SASIDEV *controller)
{
// Always successful
controller->Status();
}
int HostServices::Inquiry(const DWORD *cdb, BYTE *buf)
{
int allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8);
if (allocation_length > 4) {
if (allocation_length > 44) {
allocation_length = 44;
}
// Basic data
// buf[0] ... Processor Device
// buf[1] ... Not removable
// buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data
memset(buf, 0, allocation_length);
buf[0] = 0x03;
buf[2] = 0x01;
buf[4] = 0x1F;
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
}
return allocation_length;
}
void HostServices::StartStopUnit(SASIDEV *controller)
{
bool start = ctrl->cmd[4] & 0x01;
bool load = ctrl->cmd[4] & 0x02;
if (!start) {
// Delete all regular disk devices. This also flushes their caches.
for (auto disk : disks) {
if (disk && disk != this) {
delete disk;
}
}
if (load) {
((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::PI);
}
else {
((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::RASCSI);
}
controller->Status();
return;
}
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
}
int HostServices::AddVendorPage(int page, bool, BYTE *buf)
{
if (page == 0x20) {
// Data structure version 1.0
buf[0] = 0x01;
buf[1] = 0x00;
std::time_t t = std::time(NULL);
std::tm tm = *std::localtime(&t);
buf[2] = tm.tm_year;
buf[3] = tm.tm_mon;
buf[4] = tm.tm_mday;
buf[5] = tm.tm_hour;
buf[6] = tm.tm_min;
// Ignore leap second for simplicity
buf[7] = tm.tm_sec < 60 ? tm.tm_sec : 59;
return 8;
}
return 0;
}

View File

@ -0,0 +1,25 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include "disk.h"
class HostServices: public Disk
{
public:
HostServices() : Disk("SCHS") {};
~HostServices() {};
virtual bool Dispatch(SCSIDEV *) override;
int Inquiry(const DWORD *, BYTE *) override;
void TestUnitReady(SASIDEV *) override;
void StartStopUnit(SASIDEV *) override;
int AddVendorPage(int, bool, BYTE *) override;
};

View File

@ -11,19 +11,18 @@
#pragma once
#include "scsi_primary_commands.h"
class SASIDEV;
class ScsiBlockCommands
class ScsiBlockCommands : virtual public ScsiPrimaryCommands
{
public:
ScsiBlockCommands() {};
virtual ~ScsiBlockCommands() {};
ScsiBlockCommands() {}
virtual ~ScsiBlockCommands() {}
// Mandatory commands
virtual void TestUnitReady(SASIDEV *) = 0;
virtual void Inquiry(SASIDEV *) = 0;
virtual void ReportLuns(SASIDEV *) = 0;
virtual void FormatUnit(SASIDEV *) = 0;
virtual void ReadCapacity10(SASIDEV *) = 0;
virtual void ReadCapacity16(SASIDEV *) = 0;
@ -31,7 +30,6 @@ public:
virtual void Read16(SASIDEV *) = 0;
virtual void Write10(SASIDEV *) = 0;
virtual void Write16(SASIDEV *) = 0;
virtual void RequestSense(SASIDEV *) = 0;
// Implemented optional commands
virtual void ReadLong10(SASIDEV *) = 0;
@ -40,10 +38,6 @@ public:
virtual void ReadLong16(SASIDEV *) = 0;
virtual void WriteLong16(SASIDEV *) = 0;
virtual void Verify16(SASIDEV *) = 0;
virtual void ModeSense6(SASIDEV *) = 0;
virtual void ModeSense10(SASIDEV *) = 0;
virtual void ModeSelect6(SASIDEV *) = 0;
virtual void ModeSelect10(SASIDEV *) = 0;
virtual void ReassignBlocks(SASIDEV *) = 0;
virtual void SendDiagnostic(SASIDEV *) = 0;
virtual void StartStopUnit(SASIDEV *) = 0;

View File

@ -11,14 +11,16 @@
#pragma once
#include "scsi_primary_commands.h"
class SASIDEV;
class ScsiMmcCommands
class ScsiMmcCommands : virtual public ScsiPrimaryCommands
{
public:
ScsiMmcCommands() {};
virtual ~ScsiMmcCommands() {};
ScsiMmcCommands() {}
virtual ~ScsiMmcCommands() {}
virtual void ReadToc(SASIDEV *) = 0;
virtual void GetEventStatusNotification(SASIDEV *) = 0;

View File

@ -17,15 +17,15 @@ class ScsiPrimaryCommands
{
public:
ScsiPrimaryCommands() {};
virtual ~ScsiPrimaryCommands() {};
ScsiPrimaryCommands() {}
virtual ~ScsiPrimaryCommands() {}
// Mandatory commands
virtual void TestUnitReady(SASIDEV *) = 0;
virtual void Inquiry(SASIDEV *) = 0;
virtual void ReportLuns(SASIDEV *) = 0;
// Implemented optional commands
// Optional commands
virtual void RequestSense(SASIDEV *) = 0;
virtual void ModeSense6(SASIDEV *) = 0;
virtual void ModeSense10(SASIDEV *) = 0;

View File

@ -0,0 +1,136 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
// A basic device with mode page support, to be used for subclassing
//
//---------------------------------------------------------------------------
#include "log.h"
#include "controllers/scsidev_ctrl.h"
#include "mode_page_device.h"
using namespace std;
ModePageDevice::ModePageDevice(const string id) : PrimaryDevice(id)
{
AddCommand(ScsiDefs::eCmdModeSense6, "ModeSense6", &ModePageDevice::ModeSense6);
AddCommand(ScsiDefs::eCmdModeSense10, "ModeSense10", &ModePageDevice::ModeSense10);
AddCommand(ScsiDefs::eCmdModeSelect6, "ModeSelect6", &ModePageDevice::ModeSelect6);
AddCommand(ScsiDefs::eCmdModeSelect10, "ModeSelect10", &ModePageDevice::ModeSelect10);
}
void ModePageDevice::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (ModePageDevice::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
bool ModePageDevice::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);
(this->*command->execute)(controller);
return true;
}
// Unknown command
return false;
}
void ModePageDevice::ModeSense6(SASIDEV *controller)
{
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataIn();
}
void ModePageDevice::ModeSense10(SASIDEV *controller)
{
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataIn();
}
bool ModePageDevice::ModeSelect(const DWORD* /*cdb*/, const BYTE *buf, int length)
{
ASSERT(buf);
ASSERT(length >= 0);
// cannot be set
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
void ModePageDevice::ModeSelect6(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck6(ctrl->cmd);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataOut();
}
void ModePageDevice::ModeSelect10(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck10(ctrl->cmd);
if (ctrl->length <= 0) {
controller->Error();
return;
}
controller->DataOut();
}
int ModePageDevice::ModeSelectCheck(const DWORD *cdb, int length)
{
// Error if save parameters are set for other types than of SCHD or SCRM
if (!IsSCSIHD() && (cdb[1] & 0x01)) {
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
return length;
}
int ModePageDevice::ModeSelectCheck6(const DWORD *cdb)
{
// Receive the data specified by the parameter length
return ModeSelectCheck(cdb, cdb[4]);
}
int ModePageDevice::ModeSelectCheck10(const DWORD *cdb)
{
// Receive the data specified by the parameter length
int length = cdb[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
}
return ModeSelectCheck(cdb, length);
}

View File

@ -0,0 +1,52 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include "primary_device.h"
#include <string>
using namespace std;
class ModePageDevice: public PrimaryDevice
{
public:
ModePageDevice(const string);
virtual ~ModePageDevice() {}
virtual bool Dispatch(SCSIDEV *) override;
virtual int ModeSense6(const DWORD *, BYTE *) = 0;
virtual int ModeSense10(const DWORD *, BYTE *) = 0;
// TODO This method should not be called by SASIDEV
virtual bool ModeSelect(const DWORD *, const BYTE *, int);
private:
typedef struct _command_t {
const char* name;
void (ModePageDevice::*execute)(SASIDEV *);
_command_t(const char* _name, void (ModePageDevice::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<ScsiDefs::scsi_command, command_t*> commands;
void AddCommand(ScsiDefs::scsi_command, const char*, void (ModePageDevice::*)(SASIDEV *));
void ModeSense6(SASIDEV *) override;
void ModeSense10(SASIDEV *) override;
void ModeSelect6(SASIDEV *) override;
void ModeSelect10(SASIDEV *) override;
int ModeSelectCheck(const DWORD *, int);
int ModeSelectCheck6(const DWORD *);
int ModeSelectCheck10(const DWORD *);
};

View File

@ -0,0 +1,223 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "log.h"
#include "controllers/scsidev_ctrl.h"
#include "primary_device.h"
using namespace std;
PrimaryDevice::PrimaryDevice(const string id) : ScsiPrimaryCommands(), Device(id)
{
ctrl = NULL;
// Mandatory SCSI primary commands
AddCommand(ScsiDefs::eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
AddCommand(ScsiDefs::eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
AddCommand(ScsiDefs::eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
// Optional commands used by all RaSCSI devices
AddCommand(ScsiDefs::eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
}
void PrimaryDevice::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (PrimaryDevice::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
bool PrimaryDevice::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);
(this->*command->execute)(controller);
return true;
}
// Unknown command
return false;
}
void PrimaryDevice::TestUnitReady(SASIDEV *controller)
{
if (!CheckReady()) {
controller->Error();
return;
}
controller->Status();
}
void PrimaryDevice::Inquiry(SASIDEV *controller)
{
int lun = controller->GetEffectiveLun();
const Device *device = ctrl->unit[lun];
// Find a valid unit
// TODO The code below is probably wrong. It results in the same INQUIRY data being
// used for all LUNs, even though each LUN has its individual set of INQUIRY data.
// In addition, it supports gaps in the LUN list, which is not correct.
if (!device) {
for (int valid_lun = 0; valid_lun < SASIDEV::UnitMax; valid_lun++) {
if (ctrl->unit[valid_lun]) {
device = ctrl->unit[valid_lun];
break;
}
}
}
if (device) {
ctrl->length = Inquiry(ctrl->cmd, ctrl->buffer);
} else {
ctrl->length = 0;
}
if (ctrl->length <= 0) {
controller->Error();
return;
}
// Report if the device does not support the requested LUN
if (!ctrl->unit[lun]) {
LOGDEBUG("Reporting LUN %d for device ID %d as not supported", lun, ctrl->device->GetId());
ctrl->buffer[0] |= 0x7f;
}
controller->DataIn();
}
void PrimaryDevice::ReportLuns(SASIDEV *controller)
{
BYTE *buf = ctrl->buffer;
if (!CheckReady()) {
controller->Error();
return;
}
int allocation_length = (ctrl->cmd[6] << 24) + (ctrl->cmd[7] << 16) + (ctrl->cmd[8] << 8) + ctrl->cmd[9];
memset(buf, 0, allocation_length);
// Count number of available LUNs for the current device
int luns;
for (luns = 0; luns < controller->GetCtrl()->device->GetSupportedLuns(); luns++) {
if (!controller->GetCtrl()->unit[luns]) {
break;
}
}
// LUN list length, 8 bytes per LUN
// SCSI standard: The contents of the LUN LIST LENGTH field are not altered based on the allocation length
buf[0] = (luns * 8) >> 24;
buf[1] = (luns * 8) >> 16;
buf[2] = (luns * 8) >> 8;
buf[3] = luns * 8;
ctrl->length = allocation_length < 8 + luns * 8 ? allocation_length : 8 + luns * 8;
controller->DataIn();
}
void PrimaryDevice::RequestSense(SASIDEV *controller)
{
int lun = controller->GetEffectiveLun();
// Note: According to the SCSI specs the LUN handling for REQUEST SENSE non-existing LUNs do *not* result
// in CHECK CONDITION. Only the Sense Key and ASC are set in order to signal the non-existing LUN.
if (!ctrl->unit[lun]) {
// LUN 0 can be assumed to be present (required to call RequestSense() below)
lun = 0;
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
ctrl->status = 0x00;
}
ctrl->length = ((PrimaryDevice *)ctrl->unit[lun])->RequestSense(ctrl->cmd, ctrl->buffer);
ASSERT(ctrl->length > 0);
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
controller->DataIn();
}
bool PrimaryDevice::CheckReady()
{
// Not ready if reset
if (IsReset()) {
SetStatusCode(STATUS_DEVRESET);
SetReset(false);
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
return false;
}
// Not ready if it needs attention
if (IsAttn()) {
SetStatusCode(STATUS_ATTENTION);
SetAttn(false);
LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__);
return false;
}
// Return status if not ready
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
LOGTRACE("%s Disk not ready", __PRETTY_FUNCTION__);
return false;
}
// Initialization with no error
LOGTRACE("%s Disk is ready", __PRETTY_FUNCTION__);
return true;
}
int PrimaryDevice::RequestSense(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// Return not ready only if there are no errors
if (GetStatusCode() == STATUS_NOERROR) {
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
}
}
// Size determination (according to allocation length)
int size = (int)cdb[4];
ASSERT((size >= 0) && (size < 0x100));
// For SCSI-1, transfer 4 bytes when the size is 0
// (Deleted this specification for SCSI-2)
if (size == 0) {
size = 4;
}
// Clear the buffer
memset(buf, 0, size);
// Set 18 bytes including extended sense data
// Current error
buf[0] = 0x70;
buf[2] = (BYTE)(GetStatusCode() >> 16);
buf[7] = 10;
buf[12] = (BYTE)(GetStatusCode() >> 8);
buf[13] = (BYTE)GetStatusCode();
return size;
}

View File

@ -0,0 +1,56 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
// A device implementing mandatory SCSI primary commands, to be used for subclassing
//
//---------------------------------------------------------------------------
#pragma once
#include "controllers/sasidev_ctrl.h"
#include "interfaces/scsi_primary_commands.h"
#include "device.h"
#include <string>
#include <map>
using namespace std;
class PrimaryDevice: public Device, virtual public ScsiPrimaryCommands
{
public:
PrimaryDevice(const string);
virtual ~PrimaryDevice() {}
virtual bool Dispatch(SCSIDEV *) override;
void TestUnitReady(SASIDEV *);
void RequestSense(SASIDEV *);
bool CheckReady();
virtual int Inquiry(const DWORD *, BYTE *) = 0;
virtual int RequestSense(const DWORD *, BYTE *);
protected:
SASIDEV::ctrl_t *ctrl;
private:
typedef struct _command_t {
const char* name;
void (PrimaryDevice::*execute)(SASIDEV *);
_command_t(const char* _name, void (PrimaryDevice::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<ScsiDefs::scsi_command, command_t*> commands;
void AddCommand(ScsiDefs::scsi_command, const char*, void (PrimaryDevice::*)(SASIDEV *));
void Inquiry(SASIDEV *);
void ReportLuns(SASIDEV *);
};

View File

@ -38,13 +38,13 @@ SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
m_tap = NULL;
m_bTapEnable = false;
AddCommand(SCSIDEV::eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
AddCommand(SCSIDEV::eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
AddCommand(SCSIDEV::eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
AddCommand(SCSIDEV::eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
AddCommand(SCSIDEV::eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
AddCommand(SCSIDEV::eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
AddCommand(SCSIDEV::eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
AddCommand(ScsiDefs::eCmdTestUnitReady, "TestUnitReady", &SCSIDaynaPort::TestUnitReady);
AddCommand(ScsiDefs::eCmdRead6, "Read6", &SCSIDaynaPort::Read6);
AddCommand(ScsiDefs::eCmdWrite6, "Write6", &SCSIDaynaPort::Write6);
AddCommand(ScsiDefs::eCmdRetrieveStats, "RetrieveStats", &SCSIDaynaPort::RetrieveStatistics);
AddCommand(ScsiDefs::eCmdSetIfaceMode, "SetIfaceMode", &SCSIDaynaPort::SetInterfaceMode);
AddCommand(ScsiDefs::eCmdSetMcastAddr, "SetMcastAddr", &SCSIDaynaPort::SetMcastAddr);
AddCommand(ScsiDefs::eCmdEnableInterface, "EnableInterface", &SCSIDaynaPort::EnableInterface);
}
SCSIDaynaPort::~SCSIDaynaPort()
@ -60,7 +60,7 @@ SCSIDaynaPort::~SCSIDaynaPort()
}
}
void SCSIDaynaPort::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (SCSIDaynaPort::*execute)(SASIDEV *))
void SCSIDaynaPort::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (SCSIDaynaPort::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
@ -69,8 +69,8 @@ bool SCSIDaynaPort::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0])];
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);
@ -162,8 +162,6 @@ int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buf)
memcpy(&buf[8], GetPaddedName().c_str(), 28);
}
LOGTRACE("response size is %d", allocation_length);
return allocation_length;
}

View File

@ -33,7 +33,6 @@
#include "ctapdriver.h"
#include <map>
#include <string>
#include "../rascsi.h"
//===========================================================================
//
@ -50,11 +49,11 @@ private:
_command_t(const char* _name, void (SCSIDaynaPort::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<SCSIDEV::scsi_command, command_t*> commands;
std::map<ScsiDefs::scsi_command, command_t*> commands;
SASIDEV::ctrl_t *ctrl;
void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSIDaynaPort::*)(SASIDEV *));
void AddCommand(ScsiDefs::scsi_command, const char*, void (SCSIDaynaPort::*)(SASIDEV *));
public:
SCSIDaynaPort();

View File

@ -17,8 +17,6 @@
//---------------------------------------------------------------------------
#include "scsi_host_bridge.h"
#include "../rascsi.h"
#include "ctapdriver.h"
#include "cfilesystem.h"
#include <sstream>
@ -39,9 +37,9 @@ SCSIBR::SCSIBR() : Disk("SCBR")
fs = new CFileSys();
fs->Reset();
AddCommand(SCSIDEV::eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
AddCommand(SCSIDEV::eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
AddCommand(SCSIDEV::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
AddCommand(ScsiDefs::eCmdTestUnitReady, "TestUnitReady", &SCSIBR::TestUnitReady);
AddCommand(ScsiDefs::eCmdRead6, "GetMessage10", &SCSIBR::GetMessage10);
AddCommand(ScsiDefs::eCmdWrite6, "SendMessage10", &SCSIBR::SendMessage10);
}
SCSIBR::~SCSIBR()
@ -98,7 +96,7 @@ bool SCSIBR::Init(const map<string, string>& params)
#endif
}
void SCSIBR::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (SCSIBR::*execute)(SASIDEV *))
void SCSIBR::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (SCSIBR::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
@ -107,8 +105,8 @@ bool SCSIBR::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0])];
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);

View File

@ -20,7 +20,6 @@
#include "os.h"
#include "disk.h"
#include <string>
#include "../rascsi.h"
//===========================================================================
//
@ -40,11 +39,11 @@ private:
_command_t(const char* _name, void (SCSIBR::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<SCSIDEV::scsi_command, command_t*> commands;
std::map<ScsiDefs::scsi_command, command_t*> commands;
SASIDEV::ctrl_t *ctrl;
void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSIBR::*)(SASIDEV *));
void AddCommand(ScsiDefs::scsi_command, const char*, void (SCSIBR::*)(SASIDEV *));
public:
SCSIBR();

View File

@ -18,7 +18,6 @@
#include "fileio.h"
#include "exceptions.h"
#include <sstream>
#include "../rascsi.h"
//===========================================================================
//
@ -241,8 +240,8 @@ SCSICD::SCSICD() : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
dataindex = -1;
audioindex = -1;
AddCommand(SCSIDEV::eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
AddCommand(SCSIDEV::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
AddCommand(ScsiDefs::eCmdReadToc, "ReadToc", &SCSICD::ReadToc);
AddCommand(ScsiDefs::eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification);
}
//---------------------------------------------------------------------------
@ -260,7 +259,7 @@ SCSICD::~SCSICD()
}
}
void SCSICD::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (SCSICD::*execute)(SASIDEV *))
void SCSICD::AddCommand(ScsiDefs::scsi_command opcode, const char* name, void (SCSICD::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
@ -269,8 +268,8 @@ bool SCSICD::Dispatch(SCSIDEV *controller)
{
ctrl = controller->GetCtrl();
if (commands.count(static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0])];
if (commands.count(static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<ScsiDefs::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("%s Executing %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);

View File

@ -78,11 +78,11 @@ private:
_command_t(const char* _name, void (SCSICD::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<SCSIDEV::scsi_command, command_t*> commands;
std::map<ScsiDefs::scsi_command, command_t*> commands;
SASIDEV::ctrl_t *ctrl;
void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSICD::*)(SASIDEV *));
void AddCommand(ScsiDefs::scsi_command, const char*, void (SCSICD::*)(SASIDEV *));
public:
enum {

View File

@ -17,7 +17,6 @@
#include "fileio.h"
#include "exceptions.h"
#include <sstream>
#include "../rascsi.h"
#define DEFAULT_PRODUCT "SCSI HD"
@ -40,7 +39,7 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size)
{
// 2TB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
throw io_exception("File size must not exceed 2 TB");
throw io_exception("File size must not exceed 2 TiB");
}
// For non-removable media drives set the default product name based on the drive capacity

View File

@ -16,7 +16,6 @@
#include "scsimo.h"
#include "../rascsi.h"
#include "fileio.h"
#include "exceptions.h"
#include <sstream>

View File

@ -12,7 +12,6 @@
#include "rascsi.h"
#include "os.h"
#include "controllers/scsidev_ctrl.h"
#include "controllers/sasidev_ctrl.h"
#include "devices/device_factory.h"
#include "devices/device.h"
@ -97,7 +96,7 @@ void Banner(int argc, char* argv[])
__TIME__);
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
FPRT(stdout,"Copyright (C) 2020-2021 Contributors to the RaSCSI project\n");
FPRT(stdout,"Copyright (C) 2020-2022 Contributors to the RaSCSI project\n");
FPRT(stdout,"Connect type : %s\n", CONNECT_DESC);
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
@ -108,7 +107,7 @@ void Banner(int argc, char* argv[])
FPRT(stdout," FILE is disk image file.\n\n");
FPRT(stdout,"Usage: %s [-HDn FILE] ...\n\n", argv[0]);
FPRT(stdout," n is X68000 SASI HD number(0-15).\n");
FPRT(stdout," FILE is disk image file, \"daynaport\", or \"bridge\".\n\n");
FPRT(stdout," FILE is disk image file, \"daynaport\", \"bridge\" or \"services\".\n\n");
FPRT(stdout," Image type is detected based on file extension.\n");
FPRT(stdout," hdf : SASI HD image (XM6 SASI HD image)\n");
FPRT(stdout," hds : SCSI HD image (Non-removable generic SCSI HD image)\n");
@ -695,6 +694,9 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
}
std::map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
if (!device->SupportsFile()) {
params.erase("file");
}
if (!device->Init(params)) {
delete device;

View File

@ -24,14 +24,3 @@
#if defined(__x86_64__) || defined(__X86__)
#undef USE_SEL_EVENT_ENABLE
#endif
//---------------------------------------------------------------------------
//
// Class Declarations
//
//---------------------------------------------------------------------------
class Fileio;
// File I/O
class Disk;
// SASI/SCSI Disk
class Filepath;

View File

@ -28,6 +28,8 @@ enum PbDeviceType {
SCBR = 6;
// DaynaPort network adapter
SCDP = 7;
// Host services device
SCHS = 8;
}
// rascsi remote operations, returning PbResult

View File

@ -67,13 +67,13 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
void RascsiResponse::GetAllDeviceTypeProperties(PbDeviceTypesInfo& device_types_info)
{
GetDeviceTypeProperties(device_types_info, SAHD);
GetDeviceTypeProperties(device_types_info, SCHD);
GetDeviceTypeProperties(device_types_info, SCRM);
GetDeviceTypeProperties(device_types_info, SCMO);
GetDeviceTypeProperties(device_types_info, SCCD);
GetDeviceTypeProperties(device_types_info, SCBR);
GetDeviceTypeProperties(device_types_info, SCDP);
int ordinal = 1;
while (PbDeviceType_IsValid(ordinal)) {
PbDeviceType type = UNDEFINED;
PbDeviceType_Parse(PbDeviceType_Name(ordinal), &type);
GetDeviceTypeProperties(device_types_info, type);
ordinal++;
}
}
void RascsiResponse::GetDevice(const Device *device, PbDevice *pb_device)

View File

@ -87,6 +87,9 @@ PbDeviceType ParseType(const char *optarg)
case 'r':
return SCRM;
case 's':
return SCHS;
default:
return UNDEFINED;
}

View File

@ -14,7 +14,6 @@
#include "fileio.h"
#include "filepath.h"
#include "gpiobus.h"
#include "rascsi.h"
#include "rascsi_version.h"
//---------------------------------------------------------------------------

View File

@ -59,6 +59,10 @@ string ras_util::ListDevices(const list<PbDevice>& pb_devices)
filename = "DaynaPort SCSI/Link";
break;
case SCHS:
filename = "Host Services";
break;
default:
filename = device.file().name();
break;

View File

@ -11,7 +11,6 @@
#include "os.h"
#include "scsi.h"
#include "rascsi.h"
//---------------------------------------------------------------------------
//

View File

@ -153,3 +153,57 @@ private:
static const char* phase_str_table[];
};
class ScsiDefs {
public:
enum scsi_command : int {
eCmdTestUnitReady = 0x00,
eCmdRezero = 0x01,
eCmdRequestSense = 0x03,
eCmdFormat = 0x04,
eCmdReassign = 0x07,
eCmdRead6 = 0x08,
// DaynaPort specific command
eCmdRetrieveStats = 0x09,
eCmdWrite6 = 0x0A,
eCmdSeek6 = 0x0B,
// DaynaPort specific command
eCmdSetIfaceMode = 0x0C,
// DaynaPort specific command
eCmdSetMcastAddr = 0x0D,
// DaynaPort specific command
eCmdEnableInterface = 0x0E,
eCmdInquiry = 0x12,
eCmdModeSelect6 = 0x15,
eCmdReserve6 = 0x16,
eCmdRelease6 = 0x17,
eCmdModeSense6 = 0x1A,
eCmdStartStop = 0x1B,
eCmdSendDiag = 0x1D,
eCmdRemoval = 0x1E,
// ICD specific command
eCmdIcd = 0x1F,
eCmdReadCapacity10 = 0x25,
eCmdRead10 = 0x28,
eCmdWrite10 = 0x2A,
eCmdSeek10 = 0x2B,
eCmdVerify10 = 0x2F,
eCmdSynchronizeCache10 = 0x35,
eCmdReadDefectData10 = 0x37,
eCmdReadLong10 = 0x3E,
eCmdWriteLong10 = 0x3F,
eCmdReadToc = 0x43,
eCmdGetEventStatusNotification = 0x4A,
eCmdModeSelect10 = 0x55,
eCmdReserve10 = 0x56,
eCmdRelease10 = 0x57,
eCmdModeSense10 = 0x5A,
eCmdRead16 = 0x88,
eCmdWrite16 = 0x8A,
eCmdVerify16 = 0x8F,
eCmdSynchronizeCache16 = 0x91,
eCmdReadCapacity16_ReadLong16 = 0x9E,
eCmdWriteLong16 = 0x9F,
eCmdReportLuns = 0xA0
};
};

View File

@ -18,7 +18,6 @@
#include <sstream>
#include <iostream>
#include <getopt.h>
#include "rascsi.h"
#include <sched.h>
#include "monitor/sm_reports.h"
#include "monitor/data_sample.h"