Code cleanup, in particular related to MODE SENSE (#699)

* Replace member functions

* Fixed TODO

* Added TODOs

* Added TODOs

* Removed duplicate code

* Fixed return value

* CD-ROM mode pages are provided by the CD-ROM implementation

* MO mode pages are provided by the MO implementation

* Comment update

* Removed duplicate code

* Removed more duplicate code

* Optimization

* Updated mode page size handling

* Addec TODO

* Started more flexible mode page handling

* Map mode pages

* Page 0 must be last

* Error handling update

* Updated size handling

* Updated map handling

* Use map references

* Move superclass call

* Added comment

* Host services also support mode page 0x3f (all pages)

* Updated handling of page 0

* Removed duplicate code

* Updated buffer size handling

* Code cleanup

* Removed duplicate code

* Use calloc()

* Removed duplicate code

* Comment update

* Fixed buffer offset

* Fixed TODO

* Added buffer size check

* Comment udpate

* Logging update

* Updated logging

* Avoid potential memory leak

* Updated handling of page 0

* Added TODO

* Comment update

* Fixed error message

* Use vector instead of byte array

* Optimization

* More optimizations

* Removed duplicate code

* Do not try to add more pages when buffer is full

* Updated error message

* Comment update, fixed host services message length handling

* Code cleanup, optimizations

* Updated payload handling for page 0

* Fixed TODO

* Updated handling of PS field

* Fixed offsets

* Updated handling for page 0

* Code cleanup

* More cleanup

* Updated block descriptor handling

* Result of REPORT LUNS must not depend on whether a device is ready or not

* Printer uses a dynamically allocated buffer

* Use realloc

* Updated memory handling

* Added assertion

* Comment update

* Fixed initialization

* Reset byte transfer flag

* Updated usage of realloc

* Reverted some changes

* Re-added buffer size check

* Renaming

* Inquiry for hard disk must also work when drive is not ready

* Primary device checks EVPD

* Added page code check to Inquiry

* Explicitly set response level format

* Added comment

* Removed useless cast

* Fixed inconsistencies in setting the additional length

* Logging uodate

* Updated logging

* Made methods const

* Moved code

* Added TODO

* Added vendor page

* Reduced visibility

* Code cleanup

* Mark override

* Removed duplicate cast

* Synchronized host services mode page handling with other code

* Added TODO

* Signature update

* Moved code

* Removed duplicate code

* Fixed TODO

* Removed duplicate code

* Added buffer size check

* Improved buffer size check

* Code cleanup

* Removed useless assertions

* Cleanup

* Renaming

* Added overrides

* Removed unnecessary casts

* Cleanup

* Added TODO

* Removed obsolete memset

* Removed duplicate code

* Logging update

* Logging update

* Assertion update

* Removed useless comments

* Code cleanup

* Removed obsolete casts

* User super typedef

* Updated log messages

* Fixed #712

* Updated error handling

* Removed useless assertions

* Reduced casts to Disk*

* Updated sector size list argument

* Removed obsolete casts

* Removed comment
This commit is contained in:
Uwe Seimet 2022-02-27 22:58:01 +01:00 committed by GitHub
parent 33bfe42017
commit 0e8d89e827
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 525 additions and 875 deletions

View File

@ -115,7 +115,7 @@ void SASIDEV::Connect(int id, BUS *bus)
// Set the logical unit
//
//---------------------------------------------------------------------------
void SASIDEV::SetUnit(int no, Device *dev)
void SASIDEV::SetUnit(int no, PrimaryDevice *dev)
{
ASSERT(no < UnitMax);
@ -626,7 +626,7 @@ void SASIDEV::DataOut()
void SASIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc, ERROR_CODES::status status)
{
// Get bus information
((GPIOBUS*)ctrl.bus)->Aquire();
ctrl.bus->Aquire();
// Reset check
if (ctrl.bus->GetRST()) {
@ -664,7 +664,7 @@ void SASIDEV::CmdTestUnitReady()
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
// Command processing on drive
((Disk *)ctrl.device)->TestUnitReady(this);
ctrl.device->TestUnitReady(this);
}
//---------------------------------------------------------------------------
@ -690,7 +690,7 @@ void SASIDEV::CmdRequestSense()
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
// Command processing on drive
((Disk *)ctrl.device)->RequestSense(this);
ctrl.device->RequestSense(this);
}
//---------------------------------------------------------------------------
@ -847,8 +847,8 @@ void SASIDEV::CmdAssign()
{
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
// Command processing on drive
bool status = ((Disk *)ctrl.device)->CheckReady();
// Command processing on device
bool status = ctrl.device->CheckReady();
if (!status) {
// Failure (Error)
Error();
@ -871,8 +871,8 @@ void SASIDEV::CmdSpecify()
{
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
// Command processing on drive
bool status = ((Disk *)ctrl.device)->CheckReady();
// Command processing on device
bool status =ctrl.device->CheckReady();
if (!status) {
// Failure (Error)
Error();
@ -1143,10 +1143,12 @@ bool SASIDEV::XferOut(bool cont)
case SASIDEV::eCmdWrite16:
case SASIDEV::eCmdVerify10:
case SASIDEV::eCmdVerify16:
{
// If we're a host bridge, use the host bridge's SendMessage10 function
// TODO This class must not know about SCSIBR
if (device->IsBridge()) {
if (!((SCSIBR*)device)->SendMessage10(ctrl.cmd, ctrl.buffer)) {
SCSIBR *bridge = dynamic_cast<SCSIBR *>(device);
if (bridge) {
if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) {
// write failed
return false;
}
@ -1158,8 +1160,9 @@ bool SASIDEV::XferOut(bool cont)
// Special case Write function for DaynaPort
// TODO This class must not know about DaynaPort
if (device->IsDaynaPort()) {
if (!((SCSIDaynaPort*)device)->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) {
SCSIDaynaPort *daynaport = dynamic_cast<SCSIDaynaPort *>(device);
if (daynaport) {
if (!daynaport->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) {
// write failed
return false;
}
@ -1191,6 +1194,7 @@ bool SASIDEV::XferOut(bool cont)
// If normal, work setting
ctrl.offset = 0;
break;
}
// SPECIFY(SASI only)
case SASIDEV::eCmdInvalid:

View File

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

View File

@ -27,6 +27,7 @@
SCSIDEV::SCSIDEV() : SASIDEV()
{
scsi.is_byte_transfer = false;
scsi.bytes_to_transfer = 0;
shutdown_mode = NONE;
@ -45,6 +46,7 @@ SCSIDEV::~SCSIDEV()
void SCSIDEV::Reset()
{
scsi.is_byte_transfer = false;
scsi.bytes_to_transfer = 0;
// Work initialization
@ -63,7 +65,7 @@ BUS::phase_t SCSIDEV::Process(int initiator_id)
}
// Get bus information
((GPIOBUS*)ctrl.bus)->Aquire();
ctrl.bus->Aquire();
// Check to see if the reset signal was asserted
if (ctrl.bus->GetRST()) {
@ -356,7 +358,7 @@ void SCSIDEV::MsgOut()
void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc, ERROR_CODES::status status)
{
// Get bus information
((GPIOBUS*)ctrl.bus)->Aquire();
ctrl.bus->Aquire();
// Reset check
if (ctrl.bus->GetRST()) {
@ -402,24 +404,11 @@ void SCSIDEV::Send()
ASSERT(!ctrl.bus->GetREQ());
ASSERT(ctrl.bus->GetIO());
//if Length! = 0, send
if (ctrl.length != 0) {
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(ctrl.offset) + ", length "
+ to_string(ctrl.length)).c_str());
// TODO Get rid of Daynaport specific code in this class
// The Daynaport needs to have a delay after the size/flags field
// of the read response. In the MacOS driver, it looks like the
// driver is doing two "READ" system calls.
int len;
if (ctrl.unit[0] && ctrl.unit[0]->IsDaynaPort()) {
len = ((GPIOBUS*)ctrl.bus)->SendHandShake(
&ctrl.buffer[ctrl.offset], ctrl.length, SCSIDaynaPort::DAYNAPORT_READ_HEADER_SZ);
}
else
{
len = ctrl.bus->SendHandShake(&ctrl.buffer[ctrl.offset], ctrl.length, BUS::SEND_NO_DELAY);
}
int len = ctrl.bus->SendHandShake(&ctrl.buffer[ctrl.offset], ctrl.length, ctrl.unit[0]->GetSendDelay());
// If you cannot send all, move to status phase
if (len != (int)ctrl.length) {
@ -522,13 +511,13 @@ void SCSIDEV::Receive()
// Length != 0 if received
if (ctrl.length != 0) {
LOGTRACE("%s length is %d", __PRETTY_FUNCTION__, (int)ctrl.length);
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, (int)ctrl.length);
// Receive
len = ctrl.bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
// If not able to receive all, move to status phase
if (len != (int)ctrl.length) {
LOGERROR("%s Not able to receive %d data, only received %d. Going to error",__PRETTY_FUNCTION__, (int)ctrl.length, len);
LOGERROR("%s Not able to receive %d bytes of data, only received %d. Going to error",__PRETTY_FUNCTION__, (int)ctrl.length, len);
Error();
return;
}
@ -658,7 +647,7 @@ void SCSIDEV::Receive()
// Transfer period factor (limited to 50 x 4 = 200ns)
scsi.syncperiod = scsi.msb[i + 3];
if (scsi.syncperiod > 50) {
scsi.syncoffset = 50;
scsi.syncperiod = 50;
}
// REQ/ACK offset(limited to 16)
@ -736,13 +725,13 @@ void SCSIDEV::ReceiveBytes()
ASSERT(!ctrl.bus->GetIO());
if (ctrl.length) {
LOGTRACE("%s length is %d", __PRETTY_FUNCTION__, ctrl.length);
LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, ctrl.length);
len = ctrl.bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
// If not able to receive all, move to status phase
if (len != ctrl.length) {
LOGERROR("%s Not able to receive %d data, only received %d. Going to error",
LOGERROR("%s Not able to receive %d bytes of data, only received %d. Going to error",
__PRETTY_FUNCTION__, ctrl.length, len);
Error();
return;
@ -904,6 +893,8 @@ bool SCSIDEV::XferOut(bool cont)
ASSERT(ctrl.phase == BUS::dataout);
scsi.is_byte_transfer = false;
PrimaryDevice *device = dynamic_cast<PrimaryDevice *>(ctrl.unit[GetEffectiveLun()]);
if (device && ctrl.cmd[0] == scsi_defs::eCmdWrite6) {
return device->WriteBytes(ctrl.buffer, scsi.bytes_to_transfer);

View File

@ -184,8 +184,4 @@ public:
bool IsSASIHD() const { return type == "SAHD"; }
bool IsSCSIHD() const { return type == "SCHD" || type == "SCRM"; }
bool IsCdRom() const { return type == "SCCD"; }
bool IsMo() const { return type == "SCMO"; }
bool IsBridge() const { return type == "SCBR"; }
bool IsDaynaPort() const { return type == "SCDP"; }
};

View File

@ -31,7 +31,6 @@ DeviceFactory::DeviceFactory()
sector_sizes[SCHD] = { 512, 1024, 2048, 4096 };
sector_sizes[SCRM] = { 512, 1024, 2048, 4096 };
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
// Some old Sun CD-ROM drives support 512 bytes per sector
sector_sizes[SCCD] = { 512, 2048};
// 128 MB, 512 bytes per sector, 248826 sectors
@ -124,20 +123,17 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
try {
switch (type) {
case SAHD:
device = new SASIHD();
device = new SASIHD(sector_sizes[SAHD]);
device->SetSupportedLuns(2);
device->SetProduct("SASI HD");
((Disk *)device)->SetSectorSizes(sector_sizes[SAHD]);
break;
case SCHD: {
string ext = GetExtension(filename);
if (ext == "hdn" || ext == "hdi" || ext == "nhd") {
device = new SCSIHD_NEC();
((Disk *)device)->SetSectorSizes({ 512 });
device = new SCSIHD_NEC({ 512 });
} else {
device = new SCSIHD(false);
((Disk *)device)->SetSectorSizes(sector_sizes[SCHD]);
device = new SCSIHD(sector_sizes[SCHD], false);
// Some Apple tools require a particular drive identification
if (ext == "hda") {
@ -151,34 +147,30 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
}
case SCRM:
device = new SCSIHD(true);
device = new SCSIHD(sector_sizes[SCRM], true);
device->SetProtectable(true);
device->SetStoppable(true);
device->SetRemovable(true);
device->SetLockable(true);
device->SetProduct("SCSI HD (REM.)");
((Disk *)device)->SetSectorSizes(sector_sizes[SCRM]);
break;
case SCMO:
device = new SCSIMO();
device = new SCSIMO(sector_sizes[SCMO], geometries[SCMO]);
device->SetProtectable(true);
device->SetStoppable(true);
device->SetRemovable(true);
device->SetLockable(true);
device->SetProduct("SCSI MO");
((Disk *)device)->SetSectorSizes(sector_sizes[SCRM]);
((Disk *)device)->SetGeometries(geometries[SCMO]);
break;
case SCCD:
device = new SCSICD();
device = new SCSICD(sector_sizes[SCCD]);
device->SetReadOnly(true);
device->SetStoppable(true);
device->SetRemovable(true);
device->SetLockable(true);
device->SetProduct("SCSI CD-ROM");
((Disk *)device)->SetSectorSizes(sector_sizes[SCCD]);
break;
case SCBR:

View File

@ -38,8 +38,8 @@ Disk::Disk(const string& id) : ModePageDevice(id), ScsiBlockCommands()
dispatcher.AddCommand(eCmdRead6, "Read6", &Disk::Read6);
dispatcher.AddCommand(eCmdWrite6, "Write6", &Disk::Write6);
dispatcher.AddCommand(eCmdSeek6, "Seek6", &Disk::Seek6);
dispatcher.AddCommand(eCmdReserve6, "Reserve6", &Disk::Reserve6);
dispatcher.AddCommand(eCmdRelease6, "Release6", &Disk::Release6);
dispatcher.AddCommand(eCmdReserve6, "Reserve6", &Disk::Reserve);
dispatcher.AddCommand(eCmdRelease6, "Release6", &Disk::Release);
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &Disk::StartStopUnit);
dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &Disk::SendDiagnostic);
dispatcher.AddCommand(eCmdRemoval, "PreventAllowMediumRemoval", &Disk::PreventAllowMediumRemoval);
@ -54,8 +54,8 @@ Disk::Disk(const string& id) : ModePageDevice(id), ScsiBlockCommands()
dispatcher.AddCommand(eCmdSynchronizeCache10, "SynchronizeCache10", &Disk::SynchronizeCache10);
dispatcher.AddCommand(eCmdSynchronizeCache16, "SynchronizeCache16", &Disk::SynchronizeCache16);
dispatcher.AddCommand(eCmdReadDefectData10, "ReadDefectData10", &Disk::ReadDefectData10);
dispatcher.AddCommand(eCmdReserve10, "Reserve10", &Disk::Reserve10);
dispatcher.AddCommand(eCmdRelease10, "Release10", &Disk::Release10);
dispatcher.AddCommand(eCmdReserve10, "Reserve10", &Disk::Reserve);
dispatcher.AddCommand(eCmdRelease10, "Release10", &Disk::Release);
dispatcher.AddCommand(eCmdRead16, "Read16", &Disk::Read16);
dispatcher.AddCommand(eCmdWrite16, "Write16", &Disk::Write16);
dispatcher.AddCommand(eCmdVerify16, "Verify16", &Disk::Verify16);
@ -101,7 +101,7 @@ bool Disk::Dispatch(SCSIDEV *controller)
//---------------------------------------------------------------------------
void Disk::Open(const Filepath& path)
{
ASSERT(disk.blocks > 0);
assert(disk.blocks > 0);
SetReady(true);
@ -183,8 +183,6 @@ void Disk::Read6(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW6)) {
LOGDEBUG("%s READ(6) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Read(controller, start);
}
}
@ -193,8 +191,6 @@ void Disk::Read10(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW10)) {
LOGDEBUG("%s READ(10) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Read(controller, start);
}
}
@ -203,8 +199,6 @@ void Disk::Read16(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW16)) {
LOGDEBUG("%s READ(16) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Read(controller, start);
}
}
@ -267,8 +261,6 @@ void Disk::Write6(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW6)) {
LOGDEBUG("%s WRITE(6) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Write(controller, start);
}
}
@ -277,8 +269,6 @@ void Disk::Write10(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW10)) {
LOGDEBUG("%s WRITE(10) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Write(controller, start);
}
}
@ -287,8 +277,6 @@ void Disk::Write16(SASIDEV *controller)
{
uint64_t start;
if (GetStartAndCount(controller, start, ctrl->blocks, RW16)) {
LOGDEBUG("%s WRITE(16) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)start, ctrl->blocks);
Write(controller, start);
}
}
@ -329,8 +317,6 @@ void Disk::Verify10(SASIDEV *controller)
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW10)) {
LOGDEBUG("%s VERIFY(10) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
Verify(controller, record);
}
}
@ -340,8 +326,6 @@ void Disk::Verify16(SASIDEV *controller)
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW16)) {
LOGDEBUG("%s VERIFY(16) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
Verify(controller, record);
}
}
@ -396,7 +380,7 @@ void Disk::SynchronizeCache16(SASIDEV *controller)
void Disk::ReadDefectData10(SASIDEV *controller)
{
ctrl->length = ReadDefectData10(ctrl->cmd, ctrl->buffer);
ctrl->length = ReadDefectData10(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
if (ctrl->length <= 4) {
controller->Error();
return;
@ -438,29 +422,9 @@ int Disk::ModeSense6(const DWORD *cdb, BYTE *buf)
int length = (int)cdb[4];
memset(buf, 0, length);
// Get changeable flag
bool change = (cdb[2] & 0xc0) == 0x40;
// Get page code (0x00 is valid from the beginning)
int page = cdb[2] & 0x3f;
bool valid = page == 0x00;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
// Basic information
int size = 4;
// MEDIUM TYPE
if (IsMo()) {
// Optical reversible or erasable
buf[1] = 0x03;
}
// DEVICE SPECIFIC PARAMETER
if (IsProtected()) {
buf[2] = 0x80;
}
// Add block descriptor if DBD is 0
if ((cdb[1] & 0x08) == 0) {
// Mode parameter header, block descriptor length
@ -486,70 +450,14 @@ int Disk::ModeSense6(const DWORD *cdb, BYTE *buf)
size = 12;
}
// Page code 1 (read-write error recovery)
if (page == 0x01 || page == 0x3f) {
size += AddErrorPage(change, &buf[size]);
valid = true;
}
// Page code 3 (format device)
if (page == 0x03 || page == 0x3f) {
size += AddFormatPage(change, &buf[size]);
valid = true;
}
// Page code 4 (drive parameter)
if (page == 0x04 || page == 0x3f) {
size += AddDrivePage(change, &buf[size]);
valid = true;
}
// Page code 6 (optical)
if (IsMo()) {
if (page == 0x06 || page == 0x3f) {
size += AddOptionPage(change, &buf[size]);
valid = true;
}
}
// Page code 8 (caching)
if (page == 0x08 || page == 0x3f) {
size += AddCachePage(change, &buf[size]);
valid = true;
}
// Page code 13 (CD-ROM)
if (IsCdRom()) {
if (page == 0x0d || page == 0x3f) {
size += AddCDROMPage(change, &buf[size]);
valid = true;
}
}
// Page code 14 (CD-DA)
if (IsCdRom()) {
if (page == 0x0e || page == 0x3f) {
size += AddCDDAPage(change, &buf[size]);
valid = true;
}
}
// Page (vendor special)
int ret = AddVendorPage(page, change, &buf[size]);
if (ret > 0) {
size += ret;
valid = true;
}
if (!valid) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
SetStatusCode(STATUS_INVALIDCDB);
int pages_size = super::AddModePages(cdb, &buf[size], length - size);
if (!pages_size) {
return 0;
}
size += pages_size;
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
size = length;
}
@ -559,40 +467,18 @@ int Disk::ModeSense6(const DWORD *cdb, BYTE *buf)
return size;
}
int Disk::ModeSense10(const DWORD *cdb, BYTE *buf)
int Disk::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
{
// Get length, clear buffer
int length = cdb[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
int length = (cdb[7] << 8) | cdb[8];
if (length > max_length) {
length = max_length;
}
memset(buf, 0, length);
// Get changeable flag
bool change = (cdb[2] & 0xc0) == 0x40;
// Get page code (0x00 is valid from the beginning)
int page = cdb[2] & 0x3f;
bool valid = page == 0x00;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
// Basic Information
int size = 8;
// MEDIUM TYPE
if (IsMo()) {
// Optical reversible or erasable
buf[2] = 0x03;
}
// DEVICE SPECIFIC PARAMETER
if (IsProtected()) {
buf[3] = 0x80;
}
// Add block descriptor if DBD is 0
if ((cdb[1] & 0x08) == 0) {
// Only if ready
@ -646,70 +532,14 @@ int Disk::ModeSense10(const DWORD *cdb, BYTE *buf)
}
}
// Page code 1 (read-write error recovery)
if (page == 0x01 || page == 0x3f) {
size += AddErrorPage(change, &buf[size]);
valid = true;
}
// Page code 3 (format device)
if (page == 0x03 || page == 0x3f) {
size += AddFormatPage(change, &buf[size]);
valid = true;
}
// Page code 4 (drive parameter)
if (page == 0x04 || page == 0x3f) {
size += AddDrivePage(change, &buf[size]);
valid = true;
}
// Page code 6 (optical)
if (IsMo()) {
if (page == 0x06 || page == 0x3f) {
size += AddOptionPage(change, &buf[size]);
valid = true;
}
}
// Page code 8 (caching)
if (page == 0x08 || page == 0x3f) {
size += AddCachePage(change, &buf[size]);
valid = true;
}
// Page code 13 (CD-ROM)
if (IsCdRom()) {
if (page == 0x0d || page == 0x3f) {
size += AddCDROMPage(change, &buf[size]);
valid = true;
}
}
// Page code 14 (CD-DA)
if (IsCdRom()) {
if (page == 0x0e || page == 0x3f) {
size += AddCDDAPage(change, &buf[size]);
valid = true;
}
}
// Page (vendor special)
int ret = AddVendorPage(page, change, &buf[size]);
if (ret > 0) {
size += ret;
valid = true;
}
if (!valid) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
SetStatusCode(STATUS_INVALIDCDB);
int pages_size = super::AddModePages(cdb, &buf[size], length - size);
if (!pages_size) {
return 0;
}
size += pages_size;
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
size = length;
}
@ -720,28 +550,65 @@ int Disk::ModeSense10(const DWORD *cdb, BYTE *buf)
return size;
}
int Disk::AddErrorPage(bool change, BYTE *buf)
void Disk::SetDeviceParameters(BYTE *buf)
{
// Set the message length
buf[0] = 0x01;
buf[1] = 0x0a;
// Retry count is 0, limit time uses internal default value
return 12;
// DEVICE SPECIFIC PARAMETER
if (IsProtected()) {
buf[3] = 0x80;
}
}
int Disk::AddFormatPage(bool change, BYTE *buf)
void Disk::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
// Set the message length
buf[0] = 0x80 | 0x03;
buf[1] = 0x16;
// Page code 1 (read-write error recovery)
if (page == 0x01 || page == 0x3f) {
AddErrorPage(pages, changeable);
}
// Page code 3 (format device)
if (page == 0x03 || page == 0x3f) {
AddFormatPage(pages, changeable);
}
// Page code 4 (drive parameter)
if (page == 0x04 || page == 0x3f) {
AddDrivePage(pages, changeable);
}
// Page code 8 (caching)
if (page == 0x08 || page == 0x3f) {
AddCachePage(pages, changeable);
}
// Page (vendor special)
AddVendorPage(pages, page, changeable);
}
void Disk::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
{
vector<BYTE> buf(12);
// Retry count is 0, limit time uses internal default value
pages[1] = buf;
}
void Disk::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
{
vector<BYTE> buf(24);
// Page can be saved
buf[0] = 0x80;
// Show the number of bytes in the physical sector as changeable
// (though it cannot be changed in practice)
if (change) {
if (changeable) {
buf[0xc] = 0xff;
buf[0xd] = 0xff;
return 24;
pages[3] = buf;
return;
}
if (IsReady()) {
@ -763,18 +630,18 @@ int Disk::AddFormatPage(bool change, BYTE *buf)
buf[20] = 0x20;
}
return 24;
pages[3] = buf;
}
int Disk::AddDrivePage(bool change, BYTE *buf)
void Disk::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
{
// Set the message length
buf[0] = 0x04;
buf[1] = 0x16;
vector<BYTE> buf(24);
// No changeable area
if (change) {
return 24;
if (changeable) {
pages[4] = buf;
return;
}
if (IsReady()) {
@ -791,81 +658,30 @@ int Disk::AddDrivePage(bool change, BYTE *buf)
buf[0x5] = 0x8;
}
return 24;
pages[4] = buf;
}
int Disk::AddOptionPage(bool change, BYTE *buf)
void Disk::AddCachePage(map<int, vector<BYTE>>& pages, bool) const
{
// Set the message length
buf[0] = 0x06;
buf[1] = 0x02;
// Do not report update blocks
return 4;
}
int Disk::AddCachePage(bool change, BYTE *buf)
{
// Set the message length
buf[0] = 0x08;
buf[1] = 0x0a;
vector<BYTE> buf(12);
// Only read cache is valid, no prefetch
return 12;
pages[8] = buf;
}
int Disk::AddCDROMPage(bool change, BYTE *buf)
void Disk::AddVendorPage(map<int, vector<BYTE>>&, int, bool) const
{
// Set the message length
buf[0] = 0x0d;
buf[1] = 0x06;
// No changeable area
if (change) {
return 8;
}
// 2 seconds for inactive timer
buf[3] = 0x05;
// MSF multiples are 60 and 75 respectively
buf[5] = 60;
buf[7] = 75;
return 8;
// Nothing to add by default
}
int Disk::AddCDDAPage(bool change, BYTE *buf)
int Disk::ReadDefectData10(const DWORD *cdb, BYTE *buf, int max_length)
{
// Set the message length
buf[0] = 0x0e;
buf[1] = 0x0e;
// Audio waits for operation completion and allows
// PLAY across multiple tracks
return 16;
}
int Disk::AddVendorPage(int /*page*/, bool /*change*/, BYTE *buf)
{
ASSERT(buf);
return 0;
}
int Disk::ReadDefectData10(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// Get length, clear buffer
DWORD length = cdb[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
int length = (cdb[7] << 8) | cdb[8];
if (length > max_length) {
length = max_length;
}
ASSERT((length >= 0) && (length < 0x800));
memset(buf, 0, length);
// P/G/FORMAT
@ -909,17 +725,10 @@ bool Disk::Format(const DWORD *cdb)
return true;
}
//---------------------------------------------------------------------------
//
// READ
//
//---------------------------------------------------------------------------
// TODO Read more than one block in a single call. Currently blocked by the SASI code (missing early range check)
// and the track-oriented cache.
int Disk::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
{
ASSERT(buf);
LOGTRACE("%s", __PRETTY_FUNCTION__);
if (!CheckReady()) {
@ -939,14 +748,9 @@ int Disk::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
}
// Success
return (1 << disk.size);
return 1 << disk.size;
}
//---------------------------------------------------------------------------
//
// WRITE check
//
//---------------------------------------------------------------------------
int Disk::WriteCheck(DWORD block)
{
// Status check
@ -968,20 +772,13 @@ int Disk::WriteCheck(DWORD block)
}
// Success
return (1 << disk.size);
return 1 << disk.size;
}
//---------------------------------------------------------------------------
//
// WRITE
//
//---------------------------------------------------------------------------
// TODO Write more than one block in a single call. Currently blocked by the SASI code (missing early range check)
// and the track-oriented cache.
bool Disk::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
{
ASSERT(buf);
LOGTRACE("%s", __PRETTY_FUNCTION__);
// Error if not ready
@ -1011,6 +808,7 @@ bool Disk::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
return true;
}
// TODO For SCSI the specification mandates that the block address is verified
void Disk::Seek(SASIDEV *controller)
{
if (!CheckReady()) {
@ -1089,23 +887,13 @@ bool Disk::SendDiag(const DWORD *cdb)
void Disk::ReadCapacity10(SASIDEV *controller)
{
if (!CheckReady() || disk.blocks <= 0) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
}
BYTE *buf = ctrl->buffer;
memset(buf, 0, 8);
if (!CheckReady()) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
}
if (disk.blocks <= 0) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
LOGWARN("%s Capacity not available, medium may not be present", __PRETTY_FUNCTION__);
return;
}
// Create end of logical block address (disk.blocks-1)
uint32_t blocks = disk.blocks - 1;
buf[0] = (BYTE)(blocks >> 24);
@ -1128,15 +916,13 @@ void Disk::ReadCapacity10(SASIDEV *controller)
void Disk::ReadCapacity16(SASIDEV *controller)
{
BYTE *buf = ctrl->buffer;
memset(buf, 0, 14);
if (!CheckReady() || disk.blocks <= 0) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
}
BYTE *buf = ctrl->buffer;
// Create end of logical block address (disk.blocks-1)
uint64_t blocks = disk.blocks - 1;
buf[0] = (BYTE)(blocks >> 56);
@ -1155,6 +941,8 @@ void Disk::ReadCapacity16(SASIDEV *controller)
buf[10] = (BYTE)(length >> 8);
buf[11] = (BYTE)length;
buf[12] = 0;
// Logical blocks per physical block: not reported (1 or more)
buf[13] = 0;
@ -1184,7 +972,7 @@ void Disk::ReadCapacity16_ReadLong16(SASIDEV *controller)
//---------------------------------------------------------------------------
//
// RESERVE(6)
// RESERVE/RELEASE(6/10)
//
// The reserve/release commands are only used in multi-initiator
// environments. RaSCSI doesn't support this use case. However, some old
@ -1192,52 +980,12 @@ void Disk::ReadCapacity16_ReadLong16(SASIDEV *controller)
// just respond with an OK status.
//
//---------------------------------------------------------------------------
void Disk::Reserve6(SASIDEV *controller)
void Disk::Reserve(SASIDEV *controller)
{
controller->Status();
}
//---------------------------------------------------------------------------
//
// RESERVE(10)
//
// The reserve/release commands are only used in multi-initiator
// environments. RaSCSI doesn't support this use case. However, some old
// versions of Solaris will issue the reserve/release commands. We will
// just respond with an OK status.
//
//---------------------------------------------------------------------------
void Disk::Reserve10(SASIDEV *controller)
{
controller->Status();
}
//---------------------------------------------------------------------------
//
// RELEASE(6)
//
// The reserve/release commands are only used in multi-initiator
// environments. RaSCSI doesn't support this use case. However, some old
// versions of Solaris will issue the reserve/release commands. We will
// just respond with an OK status.
//
//---------------------------------------------------------------------------
void Disk::Release6(SASIDEV *controller)
{
controller->Status();
}
//---------------------------------------------------------------------------
//
// RELEASE(10)
//
// The reserve/release commands are only used in multi-initiator
// environments. RaSCSI doesn't support this use case. However, some old
// versions of Solaris will issue the reserve/release commands. We will
// just respond with an OK status.
//
//---------------------------------------------------------------------------
void Disk::Release10(SASIDEV *controller)
void Disk::Release(SASIDEV *controller)
{
controller->Status();
}
@ -1330,6 +1078,8 @@ bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& coun
}
}
LOGDEBUG("%s READ/WRITE/VERIFY command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, count);
// Check capacity
uint64_t capacity = GetBlockCount();
if (start > capacity || start + count > capacity) {

View File

@ -96,10 +96,8 @@ private:
void Seek10(SASIDEV *);
void ReadCapacity10(SASIDEV *) override;
void ReadCapacity16(SASIDEV *) override;
void Reserve6(SASIDEV *);
void Reserve10(SASIDEV *);
void Release6(SASIDEV *);
void Release10(SASIDEV *);
void Reserve(SASIDEV *);
void Release(SASIDEV *);
public:
@ -117,7 +115,7 @@ public:
bool SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command
virtual int Read(const DWORD *cdb, BYTE *buf, uint64_t block);
int ReadDefectData10(const DWORD *cdb, BYTE *buf);
int ReadDefectData10(const DWORD *, BYTE *, int);
uint32_t GetSectorSizeInBytes() const;
void SetSectorSizeInBytes(uint32_t, bool);
@ -138,15 +136,14 @@ public:
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);
virtual int AddVendorPage(int page, bool change, BYTE *buf);
int AddOptionPage(bool change, BYTE *buf);
int AddCachePage(bool change, BYTE *buf);
int AddCDROMPage(bool change, BYTE *buf);
int AddCDDAPage(bool, BYTE *buf);
int ModeSense10(const DWORD *cdb, BYTE *buf, int);
virtual void SetDeviceParameters(BYTE *);
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
virtual void AddErrorPage(map<int, vector<BYTE>>&, bool) const;
virtual void AddFormatPage(map<int, vector<BYTE>>&, bool) const;
virtual void AddDrivePage(map<int, vector<BYTE>>&, bool) const;
void AddCachePage(map<int, vector<BYTE>>&, bool) const;
virtual void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const;
// Internal disk data
disk_t disk;

View File

@ -101,107 +101,92 @@ void HostServices::StartStopUnit(SCSIDEV *controller)
int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf)
{
// Get length, clear buffer
// Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) {
return 0;
}
int length = (int)cdb[4];
memset(buf, 0, length);
// Get page code (0x00 is valid from the beginning)
int page = cdb[2] & 0x3f;
bool valid = page == 0x00;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
// Basic information
int size = 4;
int ret = AddRealtimeClockPage(page, &buf[size]);
if (ret > 0) {
size += ret;
valid = true;
}
if (!valid) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
SetStatusCode(STATUS_INVALIDCDB);
int pages_size = super::AddModePages(cdb, &buf[size], length - size);
if (!pages_size) {
return 0;
}
size += pages_size;
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
size = length;
}
// Final setting of mode data length
buf[0] = size;
return size;
}
int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf)
int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf, int max_length)
{
// Get length, clear buffer
int length = cdb[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
}
memset(buf, 0, length);
// Get page code (0x00 is valid from the beginning)
int page = cdb[2] & 0x3f;
bool valid = page == 0x00;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
// Basic Information
int size = 8;
int ret = AddRealtimeClockPage(page, &buf[size]);
if (ret > 0) {
size += ret;
valid = true;
}
if (!valid) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
SetStatusCode(STATUS_INVALIDCDB);
// Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) {
return 0;
}
int length = (cdb[7] << 8) | cdb[8];
if (length > max_length) {
length = max_length;
}
memset(buf, 0, length);
// Basic information
int size = 8;
int pages_size = super::AddModePages(cdb, &buf[size], length - size);
if (!pages_size) {
return 0;
}
size += pages_size;
// Do not return more than ALLOCATION LENGTH bytes
if (size > length) {
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
size = length;
}
// Final setting of mode data length
buf[0] = size >> 8;
buf[1] = size;
return size;
}
int HostServices::AddRealtimeClockPage(int page, BYTE *buf)
void HostServices::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
if (page == 0x20) {
if (page == 0x20 || page == 0x3f) {
AddRealtimeClockPage(pages, changeable);
}
}
void HostServices::AddRealtimeClockPage(map<int, vector<BYTE>>& pages, bool changeable) const
{
vector<BYTE> buf(10);
if (!changeable) {
// Data structure version 1.0
buf[0] = 0x01;
buf[1] = 0x00;
buf[2] = 0x01;
buf[3] = 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;
buf[4] = tm.tm_year;
buf[5] = tm.tm_mon;
buf[6] = tm.tm_mday;
buf[7] = tm.tm_hour;
buf[8] = tm.tm_min;
// Ignore leap second for simplicity
buf[7] = tm.tm_sec < 60 ? tm.tm_sec : 59;
return 8;
buf[9] = tm.tm_sec < 60 ? tm.tm_sec : 59;
}
return 0;
pages[32] = buf;
}

View File

@ -11,6 +11,7 @@
#pragma once
#include "mode_page_device.h"
#include <vector>
using namespace std;
@ -29,7 +30,7 @@ public:
void StartStopUnit(SCSIDEV *);
int ModeSense6(const DWORD *, BYTE *);
int ModeSense10(const DWORD *, BYTE *);
int ModeSense10(const DWORD *, BYTE *, int);
private:
@ -37,5 +38,6 @@ private:
Dispatcher<HostServices, SCSIDEV> dispatcher;
int AddRealtimeClockPage(int, BYTE *);
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
void AddRealtimeClockPage(map<int, vector<BYTE>>&, bool) const;
};

View File

@ -30,6 +30,66 @@ bool ModePageDevice::Dispatch(SCSIDEV *controller)
return dispatcher.Dispatch(this, controller) ? true : super::Dispatch(controller);
}
int ModePageDevice::AddModePages(const DWORD *cdb, BYTE *buf, int max_length)
{
bool changeable = (cdb[2] & 0xc0) == 0x40;
// Get page code (0x3f means all pages)
int page = cdb[2] & 0x3f;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
// Mode page data mapped to the respective page numbers, C++ maps are ordered by key
map<int, vector<BYTE>> pages;
AddModePages(pages, page, changeable);
// If no mode data were added at all something must be wrong
if (pages.empty()) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
int size = 0;
vector<BYTE> page0;
for (auto const& page : pages) {
if (size + (int)page.second.size() > max_length) {
LOGWARN("Mode page data size exceeds reserved buffer size");
page0.clear();
break;
}
else {
// The specification mandates that page 0 must be returned after all others
if (page.first) {
// Page data
memcpy(&buf[size], page.second.data(), page.second.size());
// Page code, PS bit may already have been set
buf[size] |= page.first;
// Page payload size
buf[size + 1] = page.second.size() - 2;
size += page.second.size();
}
else {
page0 = page.second;
}
}
}
// Page 0 must be last
if (!page0.empty()) {
memcpy(&buf[size], page0.data(), page0.size());
// Page payload size
buf[size + 1] = page0.size() - 2;
size += page0.size();
}
return size;
}
void ModePageDevice::ModeSense6(SASIDEV *controller)
{
ctrl->length = ModeSense6(ctrl->cmd, ctrl->buffer);
@ -43,7 +103,7 @@ void ModePageDevice::ModeSense6(SASIDEV *controller)
void ModePageDevice::ModeSense10(SASIDEV *controller)
{
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer);
ctrl->length = ModeSense10(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
if (ctrl->length <= 0) {
controller->Error();
return;
@ -52,12 +112,9 @@ void ModePageDevice::ModeSense10(SASIDEV *controller)
controller->DataIn();
}
bool ModePageDevice::ModeSelect(const DWORD* /*cdb*/, const BYTE *buf, int length)
bool ModePageDevice::ModeSelect(const DWORD*, const BYTE *, int)
{
ASSERT(buf);
ASSERT(length >= 0);
// cannot be set
// Cannot be set
SetStatusCode(STATUS_INVALIDPRM);
return false;
@ -67,7 +124,7 @@ void ModePageDevice::ModeSelect6(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck6(ctrl->cmd);
ctrl->length = ModeSelectCheck6();
if (ctrl->length <= 0) {
controller->Error();
return;
@ -80,7 +137,7 @@ void ModePageDevice::ModeSelect10(SASIDEV *controller)
{
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, ctrl->buffer[0]);
ctrl->length = ModeSelectCheck10(ctrl->cmd);
ctrl->length = ModeSelectCheck10();
if (ctrl->length <= 0) {
controller->Error();
return;
@ -89,11 +146,11 @@ void ModePageDevice::ModeSelect10(SASIDEV *controller)
controller->DataOut();
}
int ModePageDevice::ModeSelectCheck(const DWORD *cdb, int length)
int ModePageDevice::ModeSelectCheck(int length)
{
// Error if save parameters are set for other types than of SCHD or SCRM
// TODO This assumption is not correct, and this code should be located elsewhere
if (!IsSCSIHD() && (cdb[1] & 0x01)) {
// TODO The assumption above is not correct, and this code should be located elsewhere
if (!IsSCSIHD() && (ctrl->cmd[1] & 0x01)) {
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
@ -101,21 +158,21 @@ int ModePageDevice::ModeSelectCheck(const DWORD *cdb, int length)
return length;
}
int ModePageDevice::ModeSelectCheck6(const DWORD *cdb)
int ModePageDevice::ModeSelectCheck6()
{
// Receive the data specified by the parameter length
return ModeSelectCheck(cdb, cdb[4]);
return ModeSelectCheck(ctrl->cmd[4]);
}
int ModePageDevice::ModeSelectCheck10(const DWORD *cdb)
int ModePageDevice::ModeSelectCheck10()
{
// Receive the data specified by the parameter length
int length = cdb[7];
int length = ctrl->cmd[7];
length <<= 8;
length |= cdb[8];
if (length > 0x800) {
length = 0x800;
length |= ctrl->cmd[8];
if (length > ctrl->bufsize) {
length = ctrl->bufsize;
}
return ModeSelectCheck(cdb, length);
return ModeSelectCheck(length);
}

View File

@ -11,6 +11,8 @@
#include "primary_device.h"
#include <string>
#include <vector>
#include <map>
using namespace std;
@ -24,11 +26,16 @@ public:
virtual bool Dispatch(SCSIDEV *) override;
virtual int ModeSense6(const DWORD *, BYTE *) = 0;
virtual int ModeSense10(const DWORD *, BYTE *) = 0;
virtual int ModeSense10(const DWORD *, BYTE *, int) = 0;
// TODO This method should not be called by SASIDEV
virtual bool ModeSelect(const DWORD *, const BYTE *, int);
protected:
int AddModePages(const DWORD *, BYTE *, int);
virtual void AddModePages(map<int, vector<BYTE>>&, int, bool) const = 0;
private:
typedef PrimaryDevice super;
@ -40,7 +47,7 @@ private:
void ModeSelect6(SASIDEV *);
void ModeSelect10(SASIDEV *);
int ModeSelectCheck(const DWORD *, int);
int ModeSelectCheck6(const DWORD *);
int ModeSelectCheck10(const DWORD *);
int ModeSelectCheck(int);
int ModeSelectCheck6();
int ModeSelectCheck10();
};

View File

@ -68,11 +68,6 @@ 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);
@ -111,7 +106,7 @@ void PrimaryDevice::RequestSense(SASIDEV *controller)
}
ctrl->length = ((PrimaryDevice *)ctrl->unit[lun])->RequestSense(ctrl->cmd, ctrl->buffer);
ASSERT(ctrl->length > 0);
assert(ctrl->length > 0);
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
@ -124,7 +119,7 @@ bool PrimaryDevice::CheckReady()
if (IsReset()) {
SetStatusCode(STATUS_DEVRESET);
SetReset(false);
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
LOGTRACE("%s Device in reset", __PRETTY_FUNCTION__);
return false;
}
@ -132,26 +127,32 @@ bool PrimaryDevice::CheckReady()
if (IsAttn()) {
SetStatusCode(STATUS_ATTENTION);
SetAttn(false);
LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__);
LOGTRACE("%s Device in needs attention", __PRETTY_FUNCTION__);
return false;
}
// Return status if not ready
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
LOGTRACE("%s Disk not ready", __PRETTY_FUNCTION__);
LOGTRACE("%s Device not ready", __PRETTY_FUNCTION__);
return false;
}
// Initialization with no error
LOGTRACE("%s Disk is ready", __PRETTY_FUNCTION__);
LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__);
return true;
}
int PrimaryDevice::Inquiry(int type, int scsi_level, bool is_removable, const DWORD *cdb, BYTE *buf)
{
int allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8);
// EVPD and page code check
if ((cdb[1] & 0x01) || cdb[2]) {
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
int allocation_length = cdb[4] + (cdb[3] << 8);
if (allocation_length > 4) {
if (allocation_length > 44) {
allocation_length = 44;
@ -167,6 +168,8 @@ int PrimaryDevice::Inquiry(int type, int scsi_level, bool is_removable, const DW
buf[0] = type;
buf[1] = is_removable ? 0x80 : 0x00;
buf[2] = scsi_level;
// Response data format is SCSI-2 for devices supporting SCSI-2 or newer, otherwise it is SCSI-1-CCS
buf[3] = scsi_level >= 2 ? 2 : 0;
buf[4] = 0x1F;
// Padded vendor, product, revision
@ -178,22 +181,16 @@ int PrimaryDevice::Inquiry(int type, int scsi_level, bool is_removable, const DW
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);
}
if (GetStatusCode() == STATUS_NOERROR && !IsReady()) {
SetStatusCode(STATUS_NOTREADY);
}
// Size determination (according to allocation length)
int size = (int)cdb[4];
ASSERT((size >= 0) && (size < 0x100));
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;
}

View File

@ -37,6 +37,7 @@ public:
virtual int Inquiry(const DWORD *, BYTE *) = 0;
virtual int RequestSense(const DWORD *, BYTE *);
virtual bool WriteBytes(BYTE *, uint32_t);
virtual int GetSendDelay() { return BUS::SEND_NO_DELAY; }
protected:

View File

@ -19,26 +19,11 @@
#include "exceptions.h"
#include "../config.h"
//===========================================================================
//
// SASI Hard Disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SASIHD::SASIHD() : Disk("SAHD")
SASIHD::SASIHD(const set<uint32_t>& sector_sizes) : Disk("SAHD")
{
SetSectorSizes(sector_sizes);
}
//---------------------------------------------------------------------------
//
// Reset
//
//---------------------------------------------------------------------------
void SASIHD::Reset()
{
// Unlock, clear attention
@ -50,14 +35,9 @@ void SASIHD::Reset()
SetStatusCode(STATUS_NOERROR);
}
//---------------------------------------------------------------------------
//
// Open
//
//---------------------------------------------------------------------------
void SASIHD::Open(const Filepath& path)
{
ASSERT(!IsReady());
assert(!IsReady());
// Open as read-only
Fileio fio;
@ -101,30 +81,17 @@ void SASIHD::Open(const Filepath& path)
FileSupport::SetPath(path);
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int SASIHD::Inquiry(const DWORD* /*cdb*/, BYTE* /*buf*/)
{
SetStatusCode(STATUS_INVALIDCMD);
return 0;
}
//---------------------------------------------------------------------------
//
// REQUEST SENSE
//
//---------------------------------------------------------------------------
int SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// Size decision
int size = (int)cdb[4];
ASSERT(size >= 0 && size < 0x100);
assert(size >= 0 && size < 0x100);
// Transfer 4 bytes when size 0 (Shugart Associates System Interface specification)
if (size == 0) {

View File

@ -27,8 +27,8 @@
class SASIHD : public Disk, public FileSupport
{
public:
SASIHD();
~SASIHD() {};
SASIHD(const set<uint32_t>&);
~SASIHD() {}
void Reset();
void Open(const Filepath& path) override;

View File

@ -583,3 +583,11 @@ void SCSIDaynaPort::EnableInterface(SASIDEV *controller)
controller->Status();
}
int SCSIDaynaPort::GetSendDelay()
{
// The Daynaport needs to have a delay after the size/flags field
// of the read response. In the MacOS driver, it looks like the
// driver is doing two "READ" system calls.
return DAYNAPORT_READ_HEADER_SZ;
}

View File

@ -67,6 +67,7 @@ public:
void SetInterfaceMode(SASIDEV *);
void SetMcastAddr(SASIDEV *);
void EnableInterface(SASIDEV *);
int GetSendDelay() override;
bool Dispatch(SCSIDEV *) override;

View File

@ -121,7 +121,7 @@ int SCSIBR::Inquiry(const DWORD *cdb, BYTE *buf)
buf[0] = 0x09;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 36 - 5 + 8; // required + 8 byte extension
buf[4] = 0x1F + 8; // required + 8 byte extension
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
@ -152,13 +152,9 @@ int SCSIBR::Inquiry(const DWORD *cdb, BYTE *buf)
void SCSIBR::TestUnitReady(SASIDEV *controller)
{
// Always successful
controller->Status();}
controller->Status();
}
//---------------------------------------------------------------------------
//
// GET MESSAGE(10)
//
//---------------------------------------------------------------------------
int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
{
// Type
@ -239,16 +235,8 @@ int SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
return 0;
}
//---------------------------------------------------------------------------
//
// SEND MESSAGE(10)
//
//---------------------------------------------------------------------------
bool SCSIBR::SendMessage10(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// Type
int type = cdb[2];
@ -301,11 +289,6 @@ bool SCSIBR::SendMessage10(const DWORD *cdb, BYTE *buf)
return false;
}
//---------------------------------------------------------------------------
//
// GET MESSAGE(10)
//
//---------------------------------------------------------------------------
void SCSIBR::GetMessage10(SASIDEV *controller)
{
// Reallocate buffer (because it is not transfer for each block)
@ -365,41 +348,22 @@ void SCSIBR::SendMessage10(SASIDEV *controller)
controller->DataOut();
}
//---------------------------------------------------------------------------
//
// Get MAC Address
//
//---------------------------------------------------------------------------
int SCSIBR::GetMacAddr(BYTE *mac)
{
ASSERT(mac);
memcpy(mac, mac_addr, 6);
return 6;
}
//---------------------------------------------------------------------------
//
// Set MAC Address
//
//---------------------------------------------------------------------------
void SCSIBR::SetMacAddr(BYTE *mac)
{
ASSERT(mac);
memcpy(mac_addr, mac, 6);
}
//---------------------------------------------------------------------------
//
// Receive Packet
//
//---------------------------------------------------------------------------
void SCSIBR::ReceivePacket()
{
static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
ASSERT(tap);
assert(tap);
// previous packet has not been received
if (packet_enable) {
@ -429,15 +393,9 @@ void SCSIBR::ReceivePacket()
}
}
//---------------------------------------------------------------------------
//
// Get Packet
//
//---------------------------------------------------------------------------
void SCSIBR::GetPacketBuf(BYTE *buf)
{
ASSERT(tap);
ASSERT(buf);
assert(tap);
// Size limit
int len = packet_len;
@ -452,15 +410,9 @@ void SCSIBR::GetPacketBuf(BYTE *buf)
packet_enable = false;
}
//---------------------------------------------------------------------------
//
// Send Packet
//
//---------------------------------------------------------------------------
void SCSIBR::SendPacket(BYTE *buf, int len)
{
ASSERT(tap);
ASSERT(buf);
assert(tap);
tap->Tx(buf, len);
}
@ -472,9 +424,6 @@ void SCSIBR::SendPacket(BYTE *buf, int len)
//---------------------------------------------------------------------------
void SCSIBR::FS_InitDevice(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
fs->Reset();
fsresult = fs->InitDevice((Human68k::argument_t*)buf);
}
@ -486,13 +435,9 @@ void SCSIBR::FS_InitDevice(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_CheckDir(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -507,13 +452,9 @@ void SCSIBR::FS_CheckDir(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_MakeDir(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -528,13 +469,9 @@ void SCSIBR::FS_MakeDir(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_RemoveDir(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -549,13 +486,9 @@ void SCSIBR::FS_RemoveDir(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Rename(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -573,13 +506,9 @@ void SCSIBR::FS_Rename(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Delete(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -594,13 +523,9 @@ void SCSIBR::FS_Delete(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Attribute(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::namests_t *pNamests = (Human68k::namests_t*)&buf[i];
i += sizeof(Human68k::namests_t);
@ -619,13 +544,9 @@ void SCSIBR::FS_Attribute(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Files(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -665,13 +586,9 @@ void SCSIBR::FS_Files(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_NFiles(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -708,13 +625,9 @@ void SCSIBR::FS_NFiles(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Create(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -762,13 +675,9 @@ void SCSIBR::FS_Create(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Open(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -808,13 +717,9 @@ void SCSIBR::FS_Open(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Close(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -851,13 +756,9 @@ void SCSIBR::FS_Close(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Read(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nKey = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::fcb_t *pFcb = (Human68k::fcb_t*)&buf[i];
i += sizeof(Human68k::fcb_t);
@ -896,13 +797,9 @@ void SCSIBR::FS_Read(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Write(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nKey = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::fcb_t *pFcb = (Human68k::fcb_t*)&buf[i];
i += sizeof(Human68k::fcb_t);
@ -939,13 +836,9 @@ void SCSIBR::FS_Write(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Seek(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nKey = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::fcb_t *pFcb = (Human68k::fcb_t*)&buf[i];
i += sizeof(Human68k::fcb_t);
@ -986,13 +879,9 @@ void SCSIBR::FS_Seek(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_TimeStamp(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nKey = ntohl(*dp);
@ -1033,9 +922,6 @@ void SCSIBR::FS_TimeStamp(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_GetCapacity(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1058,13 +944,9 @@ void SCSIBR::FS_GetCapacity(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_CtrlDrive(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
Human68k::ctrldrive_t *pCtrlDrive = (Human68k::ctrldrive_t*)&buf[i];
@ -1081,9 +963,6 @@ void SCSIBR::FS_CtrlDrive(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_GetDPB(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1108,13 +987,9 @@ void SCSIBR::FS_GetDPB(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_DiskRead(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nSector = ntohl(*dp);
@ -1135,9 +1010,6 @@ void SCSIBR::FS_DiskRead(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_DiskWrite(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1151,13 +1023,9 @@ void SCSIBR::FS_DiskWrite(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Ioctrl(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
int i = 0;
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
i += sizeof(DWORD);
int i = sizeof(DWORD);
dp = (DWORD*)&buf[i];
DWORD nFunction = ntohl(*dp);
@ -1198,9 +1066,6 @@ void SCSIBR::FS_Ioctrl(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Flush(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1214,9 +1079,6 @@ void SCSIBR::FS_Flush(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_CheckMedia(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1230,9 +1092,6 @@ void SCSIBR::FS_CheckMedia(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::FS_Lock(BYTE *buf)
{
ASSERT(fs);
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
DWORD nUnit = ntohl(*dp);
@ -1246,8 +1105,6 @@ void SCSIBR::FS_Lock(BYTE *buf)
//---------------------------------------------------------------------------
int SCSIBR::ReadFsResult(BYTE *buf)
{
ASSERT(buf);
DWORD *dp = (DWORD*)buf;
*dp = htonl(fsresult);
return sizeof(DWORD);
@ -1260,8 +1117,6 @@ int SCSIBR::ReadFsResult(BYTE *buf)
//---------------------------------------------------------------------------
int SCSIBR::ReadFsOut(BYTE *buf)
{
ASSERT(buf);
memcpy(buf, fsout, fsoutlen);
return fsoutlen;
}
@ -1273,8 +1128,6 @@ int SCSIBR::ReadFsOut(BYTE *buf)
//---------------------------------------------------------------------------
int SCSIBR::ReadFsOpt(BYTE *buf)
{
ASSERT(buf);
memcpy(buf, fsopt, fsoptlen);
return fsoptlen;
}
@ -1286,8 +1139,6 @@ int SCSIBR::ReadFsOpt(BYTE *buf)
//---------------------------------------------------------------------------
void SCSIBR::WriteFs(int func, BYTE *buf)
{
ASSERT(buf);
fsresult = FS_FATAL_INVALIDCOMMAND;
fsoutlen = 0;
fsoptlen = 0;

View File

@ -17,7 +17,8 @@
// 2. The client sends the data to be printed with one or several PRINT commands. Due to
// https://github.com/akuker/RASCSI/issues/669 the maximum transfer size per PRINT command is
// limited to 4096 bytes.
// 3. The client triggers printing with SYNCHRONIZE BUFFER.
// 3. The client triggers printing with SYNCHRONIZE BUFFER. Each SYNCHRONIZE BUFFER results in
// the print command for this printer (see below) to be called for the data not yet printed.
// 4. The client releases the printer with RELEASE UNIT (optional step, mandatory for a
// multi-initiator environment).
//
@ -68,7 +69,7 @@ SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP"), ScsiPrinterCommands()
SCSIPrinter::~SCSIPrinter()
{
DiscardReservation();
Cleanup();
}
bool SCSIPrinter::Init(const map<string, string>& params)
@ -168,7 +169,7 @@ void SCSIPrinter::Print(SCSIDEV *controller)
// TODO This device suffers from the statically allocated buffer size,
// see https://github.com/akuker/RASCSI/issues/669
if (length > (uint32_t)controller->DEFAULT_BUFFER_SIZE) {
if (length > (uint32_t)ctrl->bufsize) {
LOGERROR("Transfer buffer overflow");
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);

View File

@ -176,8 +176,10 @@ bool CDTrack::IsAudio() const
//
//===========================================================================
SCSICD::SCSICD() : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
SCSICD::SCSICD(const set<uint32_t>& sector_sizes) : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
{
SetSectorSizes(sector_sizes);
// NOT in raw format
rawfile = false;
@ -262,7 +264,7 @@ void SCSICD::Open(const Filepath& path)
// Successful opening
ASSERT(GetBlockCount() > 0);
Disk::Open(path);
super::Open(path);
FileSupport::SetPath(path);
// Set RAW flag
@ -414,7 +416,7 @@ int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf)
buf[1] = 0x80;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 36 - 5; // Required
buf[4] = 0x1F;
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
@ -456,6 +458,48 @@ int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf)
return size;
}
void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
super::AddModePages(pages, page, changeable);
// Page code 13
if (page == 0x0d || page == 0x3f) {
AddCDROMPage(pages, changeable);
}
// Page code 14
if (page == 0x0e || page == 0x3f) {
AddCDDAPage(pages, changeable);
}
}
void SCSICD::AddCDROMPage(map<int, vector<BYTE>>& pages, bool changeable) const
{
vector<BYTE> buf(8);
// No changeable area
if (!changeable) {
// 2 seconds for inactive timer
buf[3] = 0x05;
// MSF multiples are 60 and 75 respectively
buf[5] = 60;
buf[7] = 75;
}
pages[13] = buf;
}
void SCSICD::AddCDDAPage(map<int, vector<BYTE>>& pages, bool) const
{
vector<BYTE> buf(16);
// Audio waits for operation completion and allows
// PLAY across multiple tracks
pages[14] = buf;
}
int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
{
ASSERT(buf);
@ -497,7 +541,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block)
// Base class
ASSERT(dataindex >= 0);
return Disk::Read(cdb, buf, block);
return super::Read(cdb, buf, block);
}
int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)

View File

@ -76,7 +76,7 @@ public:
TrackMax = 96 // Maximum number of tracks
};
SCSICD();
SCSICD(const set<uint32_t>&);
~SCSICD();
bool Dispatch(SCSIDEV *) override;
@ -88,11 +88,18 @@ public:
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override; // READ command
int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command
protected:
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
private:
typedef Disk super;
Dispatcher<SCSICD, SASIDEV> dispatcher;
void AddCDROMPage(map<int, vector<BYTE>>&, bool) const;
void AddCDDAPage(map<int, vector<BYTE>>&, bool) const;
// Open
void OpenCue(const Filepath& path); // Open(CUE)
void OpenIso(const Filepath& path); // Open(ISO)

View File

@ -26,8 +26,9 @@
//
//===========================================================================
SCSIHD::SCSIHD(bool removable) : Disk(removable ? "SCRM" : "SCHD")
SCSIHD::SCSIHD(const set<uint32_t>& sector_sizes, bool removable) : Disk(removable ? "SCRM" : "SCHD")
{
SetSectorSizes(sector_sizes);
}
void SCSIHD::FinalizeSetup(const Filepath &path, off_t size)
@ -75,7 +76,7 @@ void SCSIHD::Reset()
void SCSIHD::Open(const Filepath& path)
{
ASSERT(!IsReady());
assert(!IsReady());
// Open as read-only
Fileio fio;
@ -105,12 +106,6 @@ int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
return 0;
}
// Ready check (Error if no image file)
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
return 0;
}
// Basic data
// buf[0] ... Direct Access Device
// buf[1] ... Bit 7 set means removable
@ -121,7 +116,7 @@ int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
buf[1] = IsRemovable() ? 0x80 : 0x00;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 28 + 3; // Value close to real HDD
buf[4] = 0x1F;
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
@ -139,10 +134,9 @@ int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
bool SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
int size;
assert(length >= 0);
ASSERT(buf);
ASSERT(length >= 0);
int size;
// PF
if (cdb[1] & 0x10) {
@ -216,23 +210,19 @@ bool SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Add Vendor special page to make drive Apple compatible
//
//---------------------------------------------------------------------------
int SCSIHD::AddVendorPage(int page, bool change, BYTE *buf)
void SCSIHD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
ASSERT(buf);
// Page code 48 or 63
// Page code 48
if (page != 0x30 && page != 0x3f) {
return 0;
return;
}
// Set the message length
buf[0] = 0x30;
buf[1] = 0x1c;
vector<BYTE> buf(30);
// No changeable area
if (!change) {
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
if (!changeable) {
memcpy(&buf.data()[0xa], "APPLE COMPUTER, INC.", 20);
}
return 30;
pages[48] = buf;
}

View File

@ -22,8 +22,8 @@
class SCSIHD : public Disk, public FileSupport
{
public:
SCSIHD(bool);
virtual ~SCSIHD() {};
SCSIHD(const set<uint32_t>&, bool);
virtual ~SCSIHD() {}
void FinalizeSetup(const Filepath&, off_t);
@ -34,6 +34,5 @@ public:
virtual int Inquiry(const DWORD *cdb, BYTE *buf) override;
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
// Add vendor special page
int AddVendorPage(int page, bool change, BYTE *buf) override;
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
};

View File

@ -18,7 +18,7 @@
#include "fileio.h"
#include "exceptions.h"
SCSIHD_NEC::SCSIHD_NEC() : SCSIHD(false)
SCSIHD_NEC::SCSIHD_NEC(const set<uint32_t>& sector_sizes) : SCSIHD(sector_sizes, false)
{
// Work initialization
cylinders = 0;
@ -146,31 +146,30 @@ int SCSIHD_NEC::Inquiry(const DWORD *cdb, BYTE *buf)
return size;
}
int SCSIHD_NEC::AddErrorPage(bool change, BYTE *buf)
void SCSIHD_NEC::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
{
ASSERT(buf);
// Set the message length
buf[0] = 0x01;
buf[1] = 0x06;
vector<BYTE> buf(8);
// The retry count is 0, and the limit time uses the default value inside the device.
return 8;
pages[1] = buf;
}
int SCSIHD_NEC::AddFormatPage(bool change, BYTE *buf)
void SCSIHD_NEC::AddFormatPage(map<int, vector<BYTE>>& pages, bool changeable) const
{
ASSERT(buf);
vector<BYTE> buf(24);
// Set the message length
buf[0] = 0x80 | 0x03;
buf[1] = 0x16;
// Page can be saved
buf[0] = 0x80;
// Make the number of bytes in the physical sector appear mutable (although it cannot actually be)
if (change) {
if (changeable) {
buf[0xc] = 0xff;
buf[0xd] = 0xff;
return 24;
pages[3] = buf;
return;
}
if (IsReady()) {
@ -193,19 +192,15 @@ int SCSIHD_NEC::AddFormatPage(bool change, BYTE *buf)
buf[20] = 0x20;
}
return 24;
pages[3] = buf;
}
int SCSIHD_NEC::AddDrivePage(bool change, BYTE *buf)
void SCSIHD_NEC::AddDrivePage(map<int, vector<BYTE>>& pages, bool changeable) const
{
ASSERT(buf);
// Set the message length
buf[0] = 0x04;
buf[1] = 0x12;
vector<BYTE> buf(20);
// No changeable area
if (!change && IsReady()) {
if (!changeable && IsReady()) {
// Set the number of cylinders
buf[0x2] = (BYTE)(cylinders >> 16);
buf[0x3] = (BYTE)(cylinders >> 8);
@ -215,5 +210,5 @@ int SCSIHD_NEC::AddDrivePage(bool change, BYTE *buf)
buf[0x5] = (BYTE)heads;
}
return 20;
pages[4] = buf;
}

View File

@ -25,17 +25,17 @@
class SCSIHD_NEC : public SCSIHD
{
public:
SCSIHD_NEC();
~SCSIHD_NEC() {};
SCSIHD_NEC(const set<uint32_t>&);
~SCSIHD_NEC() {}
void Open(const Filepath& path) override;
// Commands
int Inquiry(const DWORD *cdb, BYTE *buf) override;
int AddErrorPage(bool change, BYTE *buf) override;
int AddFormatPage(bool change, BYTE *buf) override;
int AddDrivePage(bool change, BYTE *buf) override;
void AddErrorPage(map<int, vector<BYTE>>&, bool) const override;
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
void AddDrivePage(map<int, vector<BYTE>>&, bool) const override;
private:
// Geometry data

View File

@ -19,29 +19,15 @@
#include "fileio.h"
#include "exceptions.h"
//===========================================================================
//
// SCSI magneto-optical disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIMO::SCSIMO() : Disk("SCMO")
SCSIMO::SCSIMO(const set<uint32_t>& sector_sizes, const map<uint64_t, Geometry>& geometries) : Disk("SCMO")
{
SetSectorSizes(sector_sizes);
SetGeometries(geometries);
}
//---------------------------------------------------------------------------
//
// Open
//
//---------------------------------------------------------------------------
void SCSIMO::Open(const Filepath& path)
{
ASSERT(!IsReady());
assert(!IsReady());
// Open as read-only
Fileio fio;
@ -77,16 +63,8 @@ void SCSIMO::Open(const Filepath& path)
}
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIMO::Inquiry(const DWORD *cdb, BYTE *buf)
{
ASSERT(cdb);
ASSERT(buf);
// EVPD check
if (cdb[1] & 0x01) {
SetStatusCode(STATUS_INVALIDCDB);
@ -104,7 +82,7 @@ int SCSIMO::Inquiry(const DWORD *cdb, BYTE *buf)
buf[1] = 0x80;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 36 - 5; // required
buf[4] = 0x1F;
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
@ -120,16 +98,36 @@ int SCSIMO::Inquiry(const DWORD *cdb, BYTE *buf)
return size;
}
//---------------------------------------------------------------------------
//
// MODE SELECT
//
//---------------------------------------------------------------------------
void SCSIMO::SetDeviceParameters(BYTE *buf)
{
Disk::SetDeviceParameters(buf);
// MEDIUM TYPE: Optical reversible or erasable
buf[2] = 0x03;
}
void SCSIMO::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
Disk::AddModePages(pages, page, changeable);
// Page code 6
if (page == 0x06 || page == 0x3f) {
AddOptionPage(pages, changeable);
}
}
void SCSIMO::AddOptionPage(map<int, vector<BYTE>>& pages, bool) const
{
vector<BYTE> buf(4);
pages[6] = buf;
// Do not report update blocks
}
bool SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
int size;
ASSERT(buf);
ASSERT(length >= 0);
// PF
@ -191,22 +189,20 @@ bool SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Vendor Unique Format Page 20h (MO)
//
//---------------------------------------------------------------------------
int SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
void SCSIMO::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changeable) const
{
ASSERT(buf);
// Page code 20h
if ((page != 0x20) && (page != 0x3f)) {
return 0;
if (page != 0x20 && page != 0x3f) {
return;
}
// Set the message length
buf[0] = 0x20;
buf[1] = 0x0a;
vector<BYTE> buf(12);
// No changeable area
if (change) {
return 12;
if (changeable) {
pages[32] = buf;
return;
}
/*
@ -287,5 +283,7 @@ int SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
buf[11] = (BYTE)bands;
}
return 12;
pages[32] = buf;
return;
}

View File

@ -22,8 +22,8 @@
class SCSIMO : public Disk, public FileSupport
{
public:
SCSIMO();
~SCSIMO() {};
SCSIMO(const set<uint32_t>&, const map<uint64_t, Geometry>&);
~SCSIMO() {}
void Open(const Filepath& path) override;
@ -31,6 +31,14 @@ public:
int Inquiry(const DWORD *cdb, BYTE *buf) override;
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
protected:
// Internal processing
int AddVendor(int page, BOOL change, BYTE *buf); // Add vendor special page
void SetDeviceParameters(BYTE *) override;
void AddModePages(map<int, vector<BYTE>>&, int, bool) const override;
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
private:
void AddOptionPage(map<int, vector<BYTE>>&, bool) const;
};

View File

@ -488,7 +488,7 @@ public:
// Bus signal acquisition
//
//---------------------------------------------------------------------------
inline DWORD Aquire()
inline DWORD Aquire() override
{
#if defined(__x86_64__) || defined(__X86__)
// Only used for development/debugging purposes. Isn't really applicable
@ -509,24 +509,24 @@ public:
void SetENB(BOOL ast);
// Set ENB signal
bool GetBSY();
bool GetBSY() override;
// Get BSY signal
void SetBSY(bool ast);
void SetBSY(bool ast) override;
// Set BSY signal
BOOL GetSEL();
BOOL GetSEL() override;
// Get SEL signal
void SetSEL(BOOL ast);
void SetSEL(BOOL ast) override;
// Set SEL signal
BOOL GetATN();
BOOL GetATN() override;
// Get ATN signal
void SetATN(BOOL ast);
void SetATN(BOOL ast) override;
// Set ATN signal
BOOL GetACK();
BOOL GetACK() override;
// Get ACK signal
void SetACK(BOOL ast);
void SetACK(BOOL ast) override;
// Set ACK signal
BOOL GetACT();
@ -534,42 +534,42 @@ public:
void SetACT(BOOL ast);
// Set ACT signal
BOOL GetRST();
BOOL GetRST() override;
// Get RST signal
void SetRST(BOOL ast);
void SetRST(BOOL ast) override;
// Set RST signal
BOOL GetMSG();
BOOL GetMSG() override;
// Get MSG signal
void SetMSG(BOOL ast);
void SetMSG(BOOL ast) override;
// Set MSG signal
BOOL GetCD();
BOOL GetCD() override;
// Get CD signal
void SetCD(BOOL ast);
void SetCD(BOOL ast) override;
// Set CD signal
BOOL GetIO();
BOOL GetIO() override;
// Get IO signal
void SetIO(BOOL ast);
void SetIO(BOOL ast) override;
// Set IO signal
BOOL GetREQ();
BOOL GetREQ() override;
// Get REQ signal
void SetREQ(BOOL ast);
void SetREQ(BOOL ast) override;
// Set REQ signal
BYTE GetDAT();
BYTE GetDAT() override;
// Get DAT signal
void SetDAT(BYTE dat);
void SetDAT(BYTE dat) override;
// Set DAT signal
BOOL GetDP();
BOOL GetDP() override;
// Get Data parity signal
int CommandHandShake(BYTE *buf);
int CommandHandShake(BYTE *buf) override;
// Command receive handshake
int ReceiveHandShake(BYTE *buf, int count);
int ReceiveHandShake(BYTE *buf, int count) override;
// Data receive handshake
int SendHandShake(BYTE *buf, int count, int delay_after_bytes);
int SendHandShake(BYTE *buf, int count, int delay_after_bytes) override;
// Data transmission handshake
static BUS::phase_t GetPhaseRaw(DWORD raw_data);

View File

@ -772,8 +772,9 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
LOGINFO("Insert %sfile '%s' requested into %s ID %d, unit %d", pb_device.protected_() ? "protected " : "",
filename.c_str(), device->GetType().c_str(), pb_device.id(), pb_device.unit());
Disk *disk = dynamic_cast<Disk *>(device);
if (pb_device.block_size()) {
Disk *disk = dynamic_cast<Disk *>(device);
if (disk && disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(pb_device.block_size())) {
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
@ -822,7 +823,6 @@ bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device,
device->SetProtected(pb_device.protected_());
}
Disk *disk = dynamic_cast<Disk *>(device);
if (disk) {
disk->MediumChanged();
}

View File

@ -148,6 +148,7 @@ public:
virtual void SetDAT(BYTE dat) = 0;
virtual BOOL GetDP() = 0; // Get parity signal
virtual DWORD Aquire() = 0;
virtual int CommandHandShake(BYTE *buf) = 0;
virtual int ReceiveHandShake(BYTE *buf, int count) = 0;
virtual int SendHandShake(BYTE *buf, int count, int delay_after_bytes) = 0;