Feature READ/WRITE LONG(10/16) (#481)

* Partial implementation of READ/WRITE LONG(10)

* Comment update

* Comment update

* Fixed typo

* Updated dispatcher table

* Added READ/LONG(16)

* Added 16 byte opcode

* Updated flushing

* Logging update

* Fixed typo

* Check start sector

* Renaming
This commit is contained in:
Uwe Seimet 2021-11-27 05:29:21 +01:00 committed by GitHub
parent 4287145615
commit 1ad1242fad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 51 deletions

View File

@ -1227,6 +1227,7 @@ void SASIDEV::FlushUnit()
case SASIDEV::eCmdWrite6:
case SASIDEV::eCmdWrite10:
case SASIDEV::eCmdWrite16:
case SASIDEV::eCmdWriteLong16:
case SASIDEV::eCmdVerify10:
case SASIDEV::eCmdVerify16:
break;

View File

@ -77,6 +77,8 @@ private:
eCmdRead16 = 0x88,
eCmdWrite16 = 0x8A,
eCmdVerify16 = 0x8F,
eCmdWriteLong10 = 0x3F,
eCmdWriteLong16 = 0x9F,
eCmdInvalid = 0xC2,
eCmdSasiCmdAssign = 0x0E
};

View File

@ -55,8 +55,10 @@ public:
eCmdVerify10 = 0x2F,
eCmdSynchronizeCache10 = 0x35,
eCmdReadDefectData10 = 0x37,
eCmdReadLong10 = 0x3E,
eCmdWriteLong10 = 0x3F,
eCmdReadToc = 0x43,
eCmdGetEventStatusNotification = 0x4a,
eCmdGetEventStatusNotification = 0x4A,
eCmdModeSelect10 = 0x55,
eCmdReserve10 = 0x56,
eCmdRelease10 = 0x57,
@ -65,7 +67,8 @@ public:
eCmdWrite16 = 0x8A,
eCmdVerify16 = 0x8F,
eCmdSynchronizeCache16 = 0x91,
eCmdReadCapacity16 = 0x9E,
eCmdReadCapacity16_ReadLong16 = 0x9E,
eCmdWriteLong16 = 0x9F,
eCmdReportLuns = 0xA0
};

View File

@ -51,6 +51,9 @@ Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockC
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);
@ -63,7 +66,7 @@ Disk::Disk(const std::string id) : Device(id), ScsiPrimaryCommands(), ScsiBlockC
AddCommand(SCSIDEV::eCmdRead16, "Read16", &Disk::Read16);
AddCommand(SCSIDEV::eCmdWrite16, "Write16", &Disk::Write16);
AddCommand(SCSIDEV::eCmdVerify16, "Verify16", &Disk::Verify16);
AddCommand(SCSIDEV::eCmdReadCapacity16, "ReadCapacity16", &Disk::ReadCapacity16);
AddCommand(SCSIDEV::eCmdReadCapacity16_ReadLong16, "ReadCapacity16/ReadLong16", &Disk::ReadCapacity16_ReadLong16);
AddCommand(SCSIDEV::eCmdReportLuns, "ReportLuns", &Disk::ReportLuns);
}
@ -206,11 +209,6 @@ void Disk::ReassignBlocks(SASIDEV *controller)
controller->Status();
}
//---------------------------------------------------------------------------
//
// READ
//
//---------------------------------------------------------------------------
void Disk::Read(SASIDEV *controller, uint64_t record)
{
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
@ -229,42 +227,70 @@ void Disk::Read(SASIDEV *controller, uint64_t record)
void Disk::Read6(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW6)) {
LOGDEBUG("%s READ(6) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Read(controller, start);
}
}
void Disk::Read10(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW10)) {
LOGDEBUG("%s READ(10) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Read(controller, start);
}
}
void Disk::Read16(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW16)) {
LOGDEBUG("%s READ(16) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Read(controller, start);
}
}
//---------------------------------------------------------------------------
//
// WRITE
//
//---------------------------------------------------------------------------
void Disk::ReadWriteLong10(SASIDEV *controller)
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (ctrl->cmd[7] || ctrl->cmd[8]) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
return;
}
if (CheckBlockAddress(controller, RW10)) {
controller->Status();
}
}
void Disk::ReadLong10(SASIDEV *controller)
{
ReadWriteLong10(controller);
}
void Disk::ReadWriteLong16(SASIDEV *controller)
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (ctrl->cmd[12] || ctrl->cmd[13]) {
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
return;
}
if (CheckBlockAddress(controller, RW16)) {
controller->Status();
}
}
void Disk::ReadLong16(SASIDEV *controller)
{
ReadWriteLong16(controller);
}
void Disk::Write(SASIDEV *controller, uint64_t record)
{
ctrl->length = WriteCheck(record);
@ -285,42 +311,44 @@ void Disk::Write(SASIDEV *controller, uint64_t record)
void Disk::Write6(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW6)) {
LOGDEBUG("%s WRITE(6) command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Write(controller, start);
}
}
void Disk::Write10(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW10)) {
LOGDEBUG("%s WRITE(10) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Write(controller, start);
}
}
void Disk::Write16(SASIDEV *controller)
{
// Get record number and block number
uint64_t record;
if (GetStartAndCount(controller, record, ctrl->blocks, RW16)) {
LOGDEBUG("%s WRITE(16) command record=$%08X blocks=%d",__PRETTY_FUNCTION__, (uint32_t)record, ctrl->blocks);
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, record);
Write(controller, start);
}
}
//---------------------------------------------------------------------------
//
// VERIFY
//
//---------------------------------------------------------------------------
void Disk::WriteLong10(SASIDEV *controller)
{
ReadWriteLong10(controller);
}
void Disk::WriteLong16(SASIDEV *controller)
{
ReadWriteLong16(controller);
}
void Disk::Verify(SASIDEV *controller, uint64_t record)
{
// if BytChk=0
@ -1376,6 +1404,24 @@ void Disk::ReadCapacity16(SASIDEV *controller)
controller->DataIn();
}
void Disk::ReadCapacity16_ReadLong16(SASIDEV *controller)
{
// The service action determines the actual command
switch (ctrl->cmd[1] & 0x1f) {
case 0x10:
ReadCapacity16(controller);
break;
case 0x11:
ReadLong16(controller);
break;
default:
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
break;
}
}
void Disk::ReportLuns(SASIDEV *controller)
{
BYTE *buf = ctrl->buffer;
@ -1470,9 +1516,43 @@ void Disk::Release10(SASIDEV *controller)
//---------------------------------------------------------------------------
//
// Get start sector and sector count for a READ/WRITE operation
// Check/Get start sector and sector count for a READ/WRITE or READ/WRITE LONG operation
//
//---------------------------------------------------------------------------
bool Disk::CheckBlockAddress(SASIDEV *controller, access_mode mode)
{
uint64_t block = ctrl->cmd[2];
block <<= 8;
block |= ctrl->cmd[3];
block <<= 8;
block |= ctrl->cmd[4];
block <<= 8;
block |= ctrl->cmd[5];
if (mode == RW16) {
block <<= 8;
block |= ctrl->cmd[6];
block <<= 8;
block |= ctrl->cmd[7];
block <<= 8;
block |= ctrl->cmd[8];
block <<= 8;
block |= ctrl->cmd[9];
}
uint64_t capacity = GetBlockCount();
if (block > capacity) {
ostringstream s;
s << "Capacity of " << capacity << " blocks exceeded: " << "Trying to access block " << block;
LOGTRACE("%s", s.str().c_str());
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return false;
}
return true;
}
bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& count, access_mode mode)
{
if (mode == RW6) {
@ -1495,6 +1575,7 @@ bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& coun
start |= ctrl->cmd[4];
start <<= 8;
start |= ctrl->cmd[5];
if (mode == RW16) {
start <<= 8;
start |= ctrl->cmd[6];
@ -1528,7 +1609,7 @@ bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& coun
ostringstream s;
s << "Capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << start << ", block count " << ctrl->blocks;
LOGDEBUG("%s", s.str().c_str());
LOGTRACE("%s", s.str().c_str());
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return false;
}

View File

@ -101,6 +101,10 @@ public:
virtual void Write6(SASIDEV *);
void Write10(SASIDEV *) override;
void Write16(SASIDEV *) override;
void ReadLong10(SASIDEV *) override;
void ReadLong16(SASIDEV *) override;
void WriteLong10(SASIDEV *) override;
void WriteLong16(SASIDEV *) override;
void Verify10(SASIDEV *) override;
void Verify16(SASIDEV *) override;
void Seek(SASIDEV *);
@ -137,6 +141,7 @@ public:
bool SetGeometryForCapacity(uint64_t);
uint64_t GetBlockCount() const;
void SetBlockCount(uint32_t);
bool CheckBlockAddress(SASIDEV *, access_mode);
bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode);
bool CheckReady();
@ -162,6 +167,9 @@ private:
void Read(SASIDEV *, uint64_t);
void Write(SASIDEV *, uint64_t);
void Verify(SASIDEV *, uint64_t);
void ReadWriteLong10(SASIDEV *);
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);

View File

@ -34,7 +34,11 @@ public:
virtual void RequestSense(SASIDEV *) = 0;
// Implemented optional commands
virtual void ReadLong10(SASIDEV *) = 0;
virtual void WriteLong10(SASIDEV *) = 0;
virtual void Verify10(SASIDEV *) = 0;
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;

View File

@ -1551,7 +1551,7 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
//
//---------------------------------------------------------------------------
int GPIOBUS::GetCommandByteCount(BYTE opcode) {
if (opcode == 0x88 || opcode == 0x8A || opcode == 0x8F || opcode == 0x91 || opcode == 0x9E) {
if (opcode == 0x88 || opcode == 0x8A || opcode == 0x8F || opcode == 0x91 || opcode == 0x9E || opcode == 0x9F) {
return 16;
}
else if (opcode == 0xA0) {